2024-02-08 11:30:55 +01:00
<!--
Author: David Cruciani
-->
{% extends 'base.html' %}
{% block content %}
2024-02-20 14:12:26 +01:00
< br > < br >
< input type = "hidden" id = "share" value = "{{sid}}" >
< div id = "top" style = "display: ruby; margin-top: 40px;" >
2024-05-16 14:32:49 +02:00
< h2 title = "{{', '.join(query)}}" > {{query_str}}< / h2 >
2024-02-08 11:30:55 +01:00
< / div >
2024-02-22 14:35:47 +01:00
< div class = "btn-group" style = "float: right;" role = "group" aria-label = "Basic mixed styles example" >
2024-07-08 16:06:29 +02:00
< a style = "float: right;" class = "btn btn-primary" href = "/" title = "Do a new query with no relation with this one" > < i class = "fa-solid fa-plus" > < / i > New query< / a >
2024-02-22 14:35:47 +01:00
< a style = "float: right;" class = "btn btn-secondary" href = "/?query={{query}}" title = "New query with same name" > Query< / a >
2024-03-11 15:21:59 +01:00
< div class = "dropdown" style = "float: right;" >
< button class = "btn btn-primary dropdown-toggle" title = "New query with same parameters" style = "border-radius: 0;" data-bs-toggle = "dropdown" aria-expanded = "false" data-bs-auto-close = "outside" >
2024-07-08 16:06:29 +02:00
< i class = "fa-solid fa-recycle" > < / i >
2024-03-11 15:21:59 +01:00
< / button >
< div class = "dropdown-menu p-4" style = "min-width: 200px;" >
< div class = "mb-3" >
< label for = "query_as_params" class = "form-label" > To query:< / label >
2024-07-08 16:06:29 +02:00
< input type = "email" class = "form-control" id = "query_as_params" value = "{{', '.join(query)}}" >
2024-03-11 15:21:59 +01:00
< div id = "query_as_params_error" style = "color:brown" > < / div >
< / div >
< button type = "submit" class = "btn btn-primary btn-sm" @ click = "query_as_params()" style = "border-radius: 50px;" > Query< / button >
< / div >
< / div >
< / div >
2024-02-22 14:35:47 +01:00
2024-02-08 11:30:55 +01:00
2024-02-20 14:12:26 +01:00
< div class = "card card-body" >
< div class = "row" >
< div class = "col" >
< h4 > Input Attribute:< / h4 >
{{input_query}}
2024-02-08 11:30:55 +01:00
< / div >
2024-02-20 14:12:26 +01:00
< div class = "col" >
< h4 > Modules:< / h4 >
2024-02-23 14:54:51 +01:00
{{", ".join(modules)}}
2024-02-09 11:13:14 +01:00
< / div >
2024-02-08 11:30:55 +01:00
< / div >
2024-02-20 14:12:26 +01:00
< div class = "d-flex w-100 justify-content-between" >
< div > < / div >
< small > < i > {{query_date}}< / i > < / small >
< / div >
2024-02-08 11:30:55 +01:00
< / div >
2024-02-20 14:12:26 +01:00
< div style = "margin-top: 10px;" v-if = "is_searching" class = "progress" >
< div class = "progress-bar" id = "progress" role = "progressbar" aria-valuemin = "0" aria-valuemax = "100" :style = "'width:'+progress + '%;'" >
[[progress]]%
< / div >
< / div >
< span v-if = "status_site" style = "margin-left: 5px; font-size: 13px; float: right;" > [[status_site]]< / span >
2024-05-16 14:32:49 +02:00
< br >
2024-06-28 11:32:21 +02:00
< button type = "button" class = "btn btn-secondary btn-sm" @ click = "send_all = -1" title = "Send all results to an external tool" style = "float: right;" data-bs-toggle = "modal" data-bs-target = "#Send_to_modal" >
External tools
< i class = "fa-solid fa-share-from-square" > < / i >
< / button >
<!-- Modal send to -->
< div class = "modal fade" id = "Send_to_modal" tabindex = "-1" aria-labelledby = "Send_to_modalLabel" aria-hidden = "true" >
< div class = "modal-dialog modal-lg" >
< div class = "modal-content" >
< div class = "modal-header" >
< h1 class = "modal-title fs-5" id = "Send_to_modalLabel" > Send to external tools< / h1 >
< button type = "button" class = "btn-close" data-bs-dismiss = "modal" aria-label = "Close" > < / button >
< / div >
< div class = "modal-body" >
< label for = "tools_select" > Tools:< / label >
< select data-placeholder = "Tools" class = "select2-select form-control" name = "tools_select" id = "tools_select" >
< option value = "None" > --< / option >
< template v-for = "tool, key in external_tools" >
< option v-if = "tool.is_active" :value = "[[key]]" > [[tool.name]]< / option >
< / template >
< / select >
< div id = "tools_errors" class = "invalid-feedback" > < / div >
< / div >
< div class = "modal-footer" >
< button type = "button" @ click = "submit_external_tool()" class = "btn btn-primary" > Submit< / button >
< / div >
< / div >
< / div >
< / div >
2024-02-08 11:30:55 +01:00
< br / >
2024-05-16 14:32:49 +02:00
<!-- Offcanvas to navigate throw current search tree -->
2024-02-23 14:54:51 +01:00
< button class = "btn btn-outline-primary" style = "position: fixed; right: 0px; margin-top:30px" title = "Session history" data-bs-toggle = "offcanvas" data-bs-target = "#offcanvasScrolling" aria-controls = "offcanvasScrolling" >
2024-02-20 10:10:02 +01:00
< i class = "fa-solid fa-bars" > < / i >
< / button >
< div class = "offcanvas offcanvas-end" tabindex = "-1" id = "offcanvasScrolling" aria-labelledby = "offcanvasScrollingLabel" >
< div class = "offcanvas-header" >
< h5 class = "offcanvas-title" id = "offcanvasScrollingLabel" > Current History query< / h5 >
< button type = "button" class = "btn-close" data-bs-dismiss = "offcanvas" aria-label = "Close" > < / button >
< / div >
< div style = "margin-left: 18px;" >
< a class = "btn btn-secondary btn-sm" href = "/history_session" > Complete view< / a >
< / div >
< div class = "offcanvas-body" >
< ul >
2024-05-16 14:32:49 +02:00
< li v-if = "history.query" > < a :href = "'/query/'+history.uuid" :title = "'Attribute: \n' +history.input+ '\n\nModules: \n' + history.modules" > [[history.query.join(", ")]]< / a > < / li >
2024-02-20 10:10:02 +01:00
< ul >
< template v-for = "child in history.children" >
< history_view :history = "child" > < / history_view >
< / template >
< / ul >
< / ul >
< / div >
< / div >
2024-02-08 11:30:55 +01:00
<!-- Results Part -->
2024-02-12 15:36:38 +01:00
< hr >
< ul class = "nav nav-tabs" style = "margin-bottom: 10px;" >
< li class = "nav-item" >
2024-02-22 11:30:27 +01:00
< button class = "nav-link active" id = "tab-visual" @ click = "active_tab('visual')" > Visual< / button >
2024-02-12 15:36:38 +01:00
< / li >
< li class = "nav-item" >
2024-02-22 11:30:27 +01:00
< button class = "nav-link" id = "tab-json" aria-current = "page" @ click = "active_tab('json')" > Json< / button >
2024-02-19 11:21:17 +01:00
< / li >
< li class = "nav-item" >
< button class = "nav-link" id = "tab-markdown" @ click = "active_tab('markdown')" > Markdown< / button >
2024-02-12 15:36:38 +01:00
< / li >
< / ul >
2024-02-26 14:53:40 +01:00
< div class = "row" style = "margin-bottom: 50px;" >
2024-05-16 14:32:49 +02:00
< div class = "col-10" >
< div class = "accordion" v-if = "Object.keys(modules_res).length" style = "width: 95%" >
< div class = "accordion-item" :id = "'list-item-'+key_query" v-for = "ele, key_query in modules_res" >
< h2 class = "accordion-header" >
< button class = "accordion-button" data-bs-toggle = "collapse" :data-bs-target = "'#panelsStayOpenMain-'+key_query" aria-expanded = "true" :aria-controls = "'panelsStayOpenMain-'+key_query" >
[[key_query]]
< / button >
< / h2 >
< div :id = "'panelsStayOpenMain-'+key_query" class = "accordion-collapse collapse show" >
2024-06-28 11:32:21 +02:00
< button type = "button" class = "btn btn-secondary btn-sm" @ click = "send_all = key_query" title = "Send this result to an external tool" data-bs-toggle = "modal" data-bs-target = "#Send_to_modal" style = "margin-top: 5px; margin-left:5px" >
External tools
< i class = "fa-solid fa-share-from-square" > < / i >
< / button >
< div class = "accordion" style = "padding: 20px" >
2024-05-16 14:32:49 +02:00
< div class = "accordion-item" :id = "'list-item-'+key_query+'-'+key" v-for = "result, key in ele" >
< template v-if = "!('error' in result)" >
< h2 class = "accordion-header" >
< button class = "accordion-button" style = "height: 40px;" data-bs-toggle = "collapse" :data-bs-target = "'#panelsStayOpen-'+key_query+'-'+key" aria-expanded = "true" :aria-controls = "'panelsStayOpen-'+key" >
[[key]]
< / button >
< / h2 >
< div :id = "'panelsStayOpen-'+key_query+'-'+key" class = "accordion-collapse collapse show" >
<!-- visual part -->
< template v-if = "tab_list == 'visual'" >
< div class = "accordion-body" >
< template v-if = "'Object' in result.results" >
< template v-for = "obj in result.results.Object" >
< div v-html = "parseMispObject(obj, '/home/{{sid}}?query=', query_as_same)[0].outerHTML" > < / div >
< / template >
< / template >
< template v-else >
< template v-for = "misp_attrs, key_loop in result.results" >
< div v-for = "misp_attr in misp_attrs.values" class = "accordion-body" v-html = "parseMispAttr(misp_attr, misp_attrs.types, key_loop, '/home/{{sid}}?query=', query_as_same)[0].outerHTML" > < / div >
< / template >
< / template >
< / div >
2024-02-26 14:53:40 +01:00
< / template >
2024-05-16 14:32:49 +02:00
<!-- json part -->
< template v-if = "tab_list == 'json'" >
< div class = "btn-group" role = "group" style = "padding: 5px; margin-left: 5px; margin-top: 5px;" >
< a class = "btn btn-primary" :href = "`/download/${sid}?module=${key}`" title = "Download the json" > Download< / a >
< / div >
2024-02-23 14:54:51 +01:00
< div class = "accordion-body" v-html = "generateCoreFormatUI(result)[0].outerHTML" > < / div >
2024-05-16 14:32:49 +02:00
< / template >
<!-- markdown part -->
< template v-if = "tab_list == 'markdown'" >
< div class = "accordion-body" >
< template v-if = "'Object' in result.results" >
< template v-for = "obj, key_obj in result.results.Object" >
< pre >
2024-02-23 14:54:51 +01:00
#### [[obj.name]]
< template v-for = "attr, key_attr in obj.Attribute" >
###### [[attr.object_relation]]
Type: [[attr.type]]
Value: [[attr.value]]
< / template >
2024-05-16 14:32:49 +02:00
< / pre >
< hr >
< / template >
< / template >
< template v-else >
< template v-for = "misp_attrs, key_loop in result.results" >
< template v-for = "misp_attr in misp_attrs.values" >
< pre >
2024-02-26 15:35:42 +01:00
#### Attr [[key_loop +1]]
Type: [[misp_attrs.types.join(", ")]]
Value: [[misp_attr]]
2024-05-16 14:32:49 +02:00
< / pre >
< / template >
< / template >
< / template >
< / div >
2024-02-26 15:35:42 +01:00
< / template >
2024-05-16 14:32:49 +02:00
< / div >
< / template > <!-- Not error -->
2024-02-12 15:36:38 +01:00
< / div >
2024-05-16 14:32:49 +02:00
< / div > <!-- Accordion -->
2024-02-12 15:36:38 +01:00
< / div >
< / div >
2024-05-16 14:32:49 +02:00
< / div >
<!-- Errors Part -->
< hr style = "margin-top: 50px; width: 95%" >
< h3 id = "errors_part" > Errors< / h3 >
< div class = "accordion" style = "width: 95%" >
< div class = "accordion-item" :id = "'list-item-'+key_query" v-for = "ele, key_query in modules_res" >
< h2 class = "accordion-header" >
< button class = "accordion-button collapsed" data-bs-toggle = "collapse" :data-bs-target = "'#panelsStayOpenMainError-'+key_query" aria-expanded = "false" :aria-controls = "'panelsStayOpenMainError-'+key_query" >
[[key_query]]
< / button >
< / h2 >
< div :id = "'panelsStayOpenMainError-'+key_query" class = "accordion-collapse collapse" >
< div class = "accordion" style = "padding: 25px" >
< div class = "accordion-item" :id = "'list-item-'+key_query+'-'+key" v-for = "result, key in ele" >
< template v-if = "'error' in result" >
< h2 class = "accordion-header" >
< button class = "accordion-button" style = "height: 40px;" data-bs-toggle = "collapse" :data-bs-target = "'#panelsStayOpenError-'+key_query+'-'+key" aria-expanded = "false" :aria-controls = "'panelsStayOpenError-'+key_query+'-'+key" >
[[key]]
< span style = "margin-left: 5px;" title = "Error" > ❌< / span >
< / button >
< / h2 >
< div :id = "'panelsStayOpenError-'+key_query+'-'+key" class = "accordion-collapse collapse" >
< template v-if = "tab_list == 'visual' || tasb_list == 'json'" >
< div class = "accordion-body" v-html = "generateCoreFormatUI(result)[0].outerHTML" > < / div >
< / template >
< / div >
< / template >
< / div >
< / div >
< / div >
< / div >
< / div >
2024-02-12 15:36:38 +01:00
< / div >
2024-02-08 11:30:55 +01:00
2024-05-16 14:32:49 +02:00
<!-- right menu -->
< div id = "list-result" class = "list-group col-2" style = "position: fixed; right: 0px;" >
2024-02-23 14:54:51 +01:00
< template v-for = "result, key in modules_res" >
2024-05-16 14:32:49 +02:00
< a class = "btn btn-outline-primary" data-bs-toggle = "collapse" :href = "'#collapse-menu-'+key" role = "button" aria-expanded = "false" :aria-controls = "'collapse-menu-'+key" >
< template v-if = "key.length > 20" >
[[key.substring(0, 21)]]...
< / template >
< template v-else >
[[key]]
< / template >
< / a >
< div class = "collapse" :id = "'collapse-menu-'+key" >
< div class = "card card-body" >
< template v-for = "res, key_sub in result" >
< a class = "list-group-item list-group-item-action" v-if = "!('error' in res)" :href = "'#list-item-'+key+'-'+key_sub" > [[key_sub]]< / a >
< / template >
< / div >
< / div >
2024-02-23 14:54:51 +01:00
< / template >
2024-02-26 14:53:40 +01:00
< template v-if = "tab_list == 'json' || tab_list == 'visual'" >
2024-05-16 14:32:49 +02:00
< a class = "btn btn-primary" style = "background-color: #0d6efd; color:white" href = "#errors_part" > Errors< / a >
< template v-for = "result, key in modules_res" >
< a class = "btn btn-outline-primary" data-bs-toggle = "collapse" :href = "'#collapse-menu-error-'+key" role = "button" aria-expanded = "false" :aria-controls = "'collapse-menu-error-'+key" >
< template v-if = "key.length > 20" >
[[key.substring(0, 21)]]...
< / template >
< template v-else >
[[key]]
< / template >
< / a >
< div class = "collapse" :id = "'collapse-menu-error-'+key" >
< div class = "card card-body" >
< template v-for = "res, key_sub in result" >
< a class = "list-group-item list-group-item-action" v-if = "'error' in res" :href = "'#list-item-'+key+'-'+key_sub" > [[key_sub]]< / a >
< / template >
< / div >
< / div >
< / template >
2024-02-23 14:54:51 +01:00
< / template >
2024-05-16 14:32:49 +02:00
< / div >
2024-02-23 14:54:51 +01:00
< / div >
2024-02-19 11:21:17 +01:00
2024-02-08 11:30:55 +01:00
< span id = "goTop" > [< a href = "#top" > Go Back Top< / a > ]< / span >
2024-05-16 14:32:49 +02:00
< div id = "insert_form" > < / div >
2024-02-08 11:30:55 +01:00
{% endblock %}
{% block script %}
< script type = "module" >
2024-06-28 11:32:21 +02:00
const { createApp, ref, onMounted, nextTick} = Vue
2024-02-08 11:30:55 +01:00
import {message_list} from '/static/js/toaster.js'
2024-02-20 10:10:02 +01:00
import history_view from '/static/js/history/history_tree_query.js'
2024-02-08 11:30:55 +01:00
createApp({
delimiters: ['[[', ']]'],
2024-02-20 10:10:02 +01:00
components: {
history_view
},
2024-02-08 11:30:55 +01:00
setup() {
const is_searching = ref(false)
const sid = ref(null)
let last_registered = 0
const modules_res = ref({})
const progress = ref(0)
const status_site = ref()
2024-02-22 11:30:27 +01:00
const tab_list = ref("visual")
2024-02-20 10:10:02 +01:00
const history = ref({})
2024-02-22 11:31:14 +01:00
const query_info = ref({})
2024-02-08 11:30:55 +01:00
2024-06-28 11:32:21 +02:00
const external_tools = ref({})
const send_all = ref()
2024-02-08 11:30:55 +01:00
function actionQuery(){
is_searching.value = true
pollScan();
}
2024-02-22 11:31:14 +01:00
async function queryInfo(){
sid.value = $("#share").val()
let res = await fetch("/get_query_info/" + sid.value)
let loc = await res.json()
query_info.value = loc
}
2024-02-08 11:30:55 +01:00
function pollScan() {
// Loop function to update the list of identified domains
$.getJSON('/status/' + sid.value, function(data) {
progress.value = Math.round((data['complete']/data['total'])*100)
status_site.value = 'Processed ' + data['complete'] + ' of ' + data['total']
if (data['remaining'] > 0) {
setTimeout(pollScan, 3000);
} else {
2024-02-08 15:31:06 +01:00
let sum = data['complete'] - data["nb_errors"]
2024-02-08 11:30:55 +01:00
// Button Stop pressed
2024-02-08 15:31:06 +01:00
if (data['stopped']){
status_site.value = 'Stopped ! ' + sum + ' Success. ' + data["nb_errors"] + ' Errors. ' + data['complete'] + ' Total.'
// Display result of the search
}else{
status_site.value = sum + ' Success. ' + data["nb_errors"] + ' Errors. ' + data['complete'] + ' Total.'
}
2024-02-08 11:30:55 +01:00
}
if (last_registered < data [ ' registered ' ] ) {
last_registered = data['registered']
fetchResult();
}
});
}
async function fetchResult(){
modules_res.value = {}
const res = await fetch("/result/"+sid.value)
let loc = await res.json()
modules_res.value = loc
}
2024-02-19 11:21:17 +01:00
function active_tab(active_tab){
if(active_tab == "json"){
tab_list.value = "json"
2024-02-12 15:36:38 +01:00
if ( !document.getElementById("tab-json").classList.contains("active") ){
document.getElementById("tab-json").classList.add("active")
2024-02-22 11:30:27 +01:00
document.getElementById("tab-visual").classList.remove("active")
2024-02-19 11:21:17 +01:00
document.getElementById("tab-markdown").classList.remove("active")
2024-02-12 15:36:38 +01:00
}
2024-02-22 11:30:27 +01:00
}else if(active_tab == "visual"){
tab_list.value = "visual"
if ( !document.getElementById("tab-visual").classList.contains("active") ){
document.getElementById("tab-visual").classList.add("active")
2024-02-12 15:36:38 +01:00
document.getElementById("tab-json").classList.remove("active")
2024-02-19 11:21:17 +01:00
document.getElementById("tab-markdown").classList.remove("active")
}
}else if(active_tab == "markdown"){
tab_list.value = "markdown"
if ( !document.getElementById("tab-markdown").classList.contains("active") ){
document.getElementById("tab-markdown").classList.add("active")
document.getElementById("tab-json").classList.remove("active")
2024-02-22 11:30:27 +01:00
document.getElementById("tab-visual").classList.remove("active")
2024-02-12 15:36:38 +01:00
}
}
}
2024-02-20 10:10:02 +01:00
async function get_history_session(){
let res = await fetch("/get_current_query_history")
let loc = await res.json()
history.value = loc
}
2024-03-11 15:21:59 +01:00
// query 'value' with same parameters with a parent
2024-02-22 11:31:14 +01:00
async function query_as_same(value){
let result_dict = {"modules": query_info.value["modules"],
"input": query_info.value["input_query"],
2024-05-16 14:32:49 +02:00
"query": [value],
2024-02-22 11:31:14 +01:00
"parent_id": sid.value,
"query_as_same": true,
"config": {}
}
const res = await fetch('/run_modules',{
headers: { "X-CSRFToken": $("#csrf_token").val(), "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify(result_dict)
})
if(await res.status == 201){
let loc = await res.json()
await nextTick()
window.location.href="/query/" + loc['id']
}
}
2024-03-11 15:21:59 +01:00
// query 'value' with same parameters without a parent
async function query_as_params(){
let loc = $("#query_as_params").val()
2024-05-16 14:32:49 +02:00
loc = loc.split(', ')
2024-03-11 15:21:59 +01:00
$("#query_as_params_error").text("")
if(loc){
2024-06-28 11:32:21 +02:00
let result_dict = {
"modules": query_info.value["modules"],
"input": query_info.value["input_query"],
"query": loc,
"config": {},
"same_query_id": sid.value,
"parent_id": ""
}
2024-03-11 15:21:59 +01:00
const res = await fetch('/run_modules',{
headers: { "X-CSRFToken": $("#csrf_token").val(), "Content-Type": "application/json" },
method: "POST",
body: JSON.stringify(result_dict)
})
if(await res.status == 201){
let loc = await res.json()
await nextTick()
window.location.href="/query/" + loc['id']
}
}else{
$("#query_as_params_error").text("Please give value")
}
}
2024-06-28 11:32:21 +02:00
async function fetch_external_tools(){
const res = await fetch("/external_tools/list")
if(await res.status==400 ){
display_toast(res)
}else{
let loc = await res.json()
external_tools.value = loc
}
2024-05-16 14:32:49 +02:00
}
2024-06-28 11:32:21 +02:00
fetch_external_tools()
2024-05-16 14:32:49 +02:00
2024-06-28 11:32:21 +02:00
async function submit_external_tool(){
let tool_selected = $("#tools_select").val()
if(tool_selected != 'None'){
let to_return = {}
if(send_all.value != -1){
to_return[send_all.value] = modules_res.value[send_all.value]
}else{
to_return = modules_res.value
}
2024-05-16 14:32:49 +02:00
2024-06-28 11:32:21 +02:00
$('#insert_form').append(
$('< form > ').attr(
{"action": external_tools.value[tool_selected].url, "name": "external_tools_form", "method": "post", "style": "display:none"}).append(
$("< input > ").attr({"type": "text", "name": "results"}).val(JSON.stringify(to_return)
)
)
);
document.forms['external_tools_form'].submit();
}
2024-05-16 14:32:49 +02:00
}
2024-02-08 11:30:55 +01:00
onMounted(() => {
2024-02-22 11:31:14 +01:00
queryInfo()
2024-02-08 11:30:55 +01:00
actionQuery()
2024-02-20 10:10:02 +01:00
get_history_session()
2024-02-22 11:31:14 +01:00
window._query_as_same = query_as_same
2024-06-28 11:32:21 +02:00
$('.select2-select').select2({
theme: 'bootstrap-5',
width: '50%'
})
2024-02-08 11:30:55 +01:00
})
return {
message_list,
2024-02-23 14:54:51 +01:00
sid,
2024-02-22 11:31:14 +01:00
query_info,
2024-02-08 11:30:55 +01:00
progress,
status_site,
is_searching,
modules_res,
2024-02-19 11:21:17 +01:00
tab_list,
2024-02-20 10:10:02 +01:00
history,
2024-02-12 15:36:38 +01:00
generateCoreFormatUI,
2024-02-22 11:30:27 +01:00
parseMispObject,
2024-02-26 14:53:40 +01:00
parseMispAttr,
2024-06-28 11:32:21 +02:00
external_tools,
send_all,
2024-02-22 11:30:27 +01:00
active_tab,
2024-03-11 15:21:59 +01:00
query_as_same,
2024-05-16 14:32:49 +02:00
query_as_params,
2024-06-28 11:32:21 +02:00
submit_external_tool
2024-02-08 11:30:55 +01:00
}
}
2024-02-19 14:01:06 +01:00
}).mount('.container-fluid')
2024-02-08 11:30:55 +01:00
< / script >
{% endblock %}