Browse Source

Formular Grafikelemente laden aus JSON Export #5

viz_kern51
Daniel Quathamer 3 months ago
parent
commit
0457923d26
  1. 653
      src-modules/module/viz/schluesseltabellen/viz_type_plot_fuellen.sql
  2. 77
      test/webapps_superx/test_viz/stud_zeitreihe_plot.html

653
src-modules/module/viz/schluesseltabellen/viz_type_plot_fuellen.sql

@ -0,0 +1,653 @@
--Freemarker Template
<#include "SQL_lingua_franca"/>
<#include "SuperX_general"/>
<sqlvars>
<sqlvar name="renderer_plot_id">
select tid from viz_renderer where uniquename='plot';
</sqlvar>
</sqlvars>
<#assign viz_types = [
{"uniquename":"bar_x", "caption":"Balkendiagramm (horizontal)",
"orientation":"H",
"description":"Horizontales Balkendiagramm"},
{"uniquename":"bar_y", "caption":"Balkendiagramm (vertikal)",
"orientation":"V",
"description":"Vertikales Balkendiagramm"},
{"uniquename":"line", "caption":"Linien (vertikal)",
"orientation":"V",
"description":"Vertikales Liniendiagramm"},
{"uniquename":"area_x", "caption":"Flächendiagramm (horizontal)",
"orientation":"H",
"description":"Horizontales Flächendiagramm"},
{"uniquename":"area_y", "caption":"Flächendiagramm (vertikal)",
"orientation":"V",
"description":"Vertikales Flächendiagramm"},
{"uniquename":"dot", "caption":"Punkte (vertikal)",
"orientation":"V",
"description":"Vertikales Punktdiagramm"},
{"uniquename":"box_x", "caption":"Boxplot (horizontal)",
"orientation":"H",
"description":"Horizontales Boxplot"},
{"uniquename":"box_y", "caption":"Boxplot (vertikal)",
"orientation":"V",
"description":"Vertikales Boxplot"},
,
{"uniquename":"text", "caption":"Wertelabel (vertikal)",
"orientation":"V",
"description":"Wertelabel für vertikales Diagramm"}
]
/>
<#assign viz_properties = [
{ "caption":"X-Achse",
"prop_uniquename":"x",
"explanation":"X-Achsendefinition",
"prop_default":"",
"prop_unit":"",
"is_generic":"0",
"static_values":"",
"is_mandatory":"0",
"input_type_uniquename":"TEXT",
"property_group_uniquename":"CATEGORY",
"sortnr":"",
"range_from":"",
"range_to":"",
"prop_value_type":"STRING"
},
{ "caption":"Y-Achse",
"prop_uniquename":"y",
"explanation":"Y-Achsendefinition",
"prop_default":"",
"prop_unit":"",
"is_generic":"0",
"static_values":"",
"is_mandatory":"0",
"input_type_uniquename":"TEXT",
"property_group_uniquename":"CATEGORY",
"sortnr":"",
"range_from":"",
"range_to":"",
"prop_value_type":"STRING"
}
,
{ "caption":"Serien-Dimension",
"prop_uniquename":"stroke",
"explanation":"Serien-Dimension zusätzlich zu Achsen",
"prop_default":"",
"prop_unit":"",
"is_generic":"0",
"static_values":"",
"is_mandatory":"0",
"input_type_uniquename":"TEXT",
"property_group_uniquename":"CATEGORY",
"sortnr":"",
"range_from":"",
"range_to":"",
"prop_value_type":"STRING"
}
,
{ "caption":"Flächenfarbe",
"prop_uniquename":"fill_static",
"explanation":"Nur für Grafikelemente Flächen und Balken. Füllfarbe.",
"prop_default":"",
"prop_unit":"",
"is_generic":"0",
"static_values":"",
"is_mandatory":"0",
"input_type_uniquename":"COLOR",
"property_group_uniquename":"STYLE",
"sortnr":"",
"range_from":"",
"range_to":"",
"prop_value_type":"STRING",
"variable_name":"fill"
},
{ "caption":"Beschriftung",
"prop_uniquename":"text",
"explanation":"Nur für Grafikelement Wertelabel",
"prop_default":"",
"prop_unit":"",
"is_generic":"0",
"static_values":"",
"is_mandatory":"0",
"input_type_uniquename":"TEXT",
"property_group_uniquename":"CATEGORY",
"sortnr":"",
"range_from":"",
"range_to":"",
"prop_value_type":"STRING"
}
]
/>
<#assign viz_type_properties = [
{ "viz_type_uniquename":"bar_x",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"bar_x",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"bar_x",
"viz_property_uniquename":"stroke",
"is_mandatory":"0",
"sortnr":"20"},
{ "viz_type_uniquename":"bar_y",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"bar_y",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"bar_y",
"viz_property_uniquename":"stroke",
"is_mandatory":"0",
"sortnr":"20"},
{ "viz_type_uniquename":"line",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"line",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"line",
"viz_property_uniquename":"stroke",
"is_mandatory":"0",
"sortnr":"20"},
{ "viz_type_uniquename":"dot",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"dot",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"dot",
"viz_property_uniquename":"stroke",
"is_mandatory":"0",
"sortnr":"20"},
{ "viz_type_uniquename":"box_x",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"box_x",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"box_y",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"box_y",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"text",
"viz_property_uniquename":"x",
"is_mandatory":"1",
"sortnr":"1"},
{ "viz_type_uniquename":"text",
"viz_property_uniquename":"y",
"is_mandatory":"1",
"sortnr":"10"},
{ "viz_type_uniquename":"text",
"viz_property_uniquename":"stroke",
"is_mandatory":"0",
"sortnr":"20"},
{ "viz_type_uniquename":"text",
"viz_property_uniquename":"text",
"is_mandatory":"0",
"sortnr":"30"}
]
/>
<#assign viz_type_properties_general = [
{ "caption":"Strichlinie Abstand-Intervalle",
"prop_uniquename":"strokeDasharray",
"explanation":"Abstand von Bindestrichen (Komma-separierte Pixel), z.B. [10,5] für 10 und dann 5 Pixel Abstand",
"prop_default":"",
"prop_unit":"",
"is_generic":"0",
"static_values":"",
"is_mandatory":"0",
"input_type_uniquename":"TEXT",
"property_group_uniquename":"STYLE",
"sortnr":"",
"range_from":"",
"range_to":"",
"prop_value_type":"STRING"
}
] />
--ab hier nicht mehr ändern:
--Die Sortierunmmer ergibt sich aus der Reihenfolge
--daher hier mit Bedacht ändern:
<@create_temp_tables />
<@fill_viz_properties />
<#foreach viz_type in viz_types>
<@fill_viz_type_properties_general viz_type_p=viz_type />
<@fill_viz_type_properties viz_type_p=viz_type />
</#foreach>
<@drop_temp_tables />
<#macro fill_viz_type_properties_general viz_type_p>
select 'Befülle Grafikelement ${viz_type_p.caption}' from xdummy;
delete from tmp_viz_type;
insert into tmp_viz_type(tid,
uniquename,
caption,
renderer_id,
-- srcpath,
-- method,
orientation)
select T.tid,
'${viz_type_p.uniquename}',
'${viz_type_p.caption}',
${renderer_plot_id},
'${viz_type_p.orientation}'
from xdummy left outer join viz_type T on (
T.uniquename='${viz_type_p.uniquename}'
and T.renderer_id=${renderer_plot_id}
)
;
insert into viz_type(
uniquename,
caption,
renderer_id,
-- srcpath,
-- method,
orientation)
select uniquename,
caption,
renderer_id,
-- srcpath,
-- method,
orientation
from tmp_viz_type T
where T.tid is null;
update viz_type set
uniquename=T.uniquename,
caption=T.caption,
renderer_id=T.renderer_id,
-- srcpath,
-- method,
orientation=T.orientation
from tmp_viz_type T
where T.tid=viz_type.tid
and viz_type.tid in (select distinct T.tid from tmp_viz_type);
delete from viz_type_property
where (viz_type_id,
viz_property_id)
in (select Y.tid as viz_type_id,
P.tid as viz_property_id
from tmp_viz_property T,viz_type Y, viz_property P
where Y.uniquename='${viz_type_p.uniquename}'
and Y.renderer_id=${renderer_plot_id}
and P.prop_uniquename=T.prop_uniquename
and T.is_general=1)
;
insert into viz_type_property(
viz_type_id,
viz_property_id,
is_mandatory,
sortnr)
select Y.tid as viz_type_id,
P.tid as viz_property_id,
P.is_mandatory,
T.sortnr
from tmp_viz_property T,viz_type Y, viz_property P
where Y.uniquename='${viz_type_p.uniquename}'
and Y.renderer_id=${renderer_plot_id}
and P.prop_uniquename=T.prop_uniquename
and T.is_general=1;
</#macro>
<#macro fill_viz_type_properties viz_type_p>
<#foreach viz_prop in viz_type_properties>
<#if viz_prop.viz_type_uniquename==viz_type_p.uniquename >
delete from viz_type_property
where (viz_type_id,
viz_property_id)
in (select Y.tid as viz_type_id,
P.tid as viz_property_id
from viz_type Y, viz_property P
where Y.uniquename='${viz_type_p.uniquename}'
and Y.renderer_id=${renderer_plot_id}
and P.prop_uniquename='${viz_prop.viz_property_uniquename}') ;
insert into viz_type_property(
viz_type_id,
viz_property_id,
is_mandatory,
sortnr)
select Y.tid as viz_type_id,
P.tid as viz_property_id,
${viz_prop.is_mandatory},
${viz_prop.sortnr}
from viz_type Y, viz_property P
where Y.uniquename='${viz_type_p.uniquename}'
and Y.renderer_id=${renderer_plot_id}
and P.prop_uniquename='${viz_prop.viz_property_uniquename}'
;
</#if>
</#foreach>
</#macro>
<#macro create_temp_tables>
CREATE temp TABLE tmp_viz_type
(
tid serial NOT NULL,
uniquename varchar(255) NOT NULL,
caption varchar(255),
renderer_id integer,
srcpath varchar(255),
method varchar(255),
orientation char(1),
description text
);
CREATE temp TABLE tmp_viz_type_property
(
tid serial NOT NULL,
viz_type_id integer,
viz_property_id integer,
is_mandatory smallint DEFAULT 0,
sortnr smallint DEFAULT 0
);
CREATE temp TABLE tmp_viz_property_renderer
(
tid serial NOT NULL,
renderer_id integer NOT NULL,
property_id integer NOT NULL,
variable_name varchar(255)
);
create temp table tmp_viz_property_group
(
tid serial NOT NULL,
uniquename varchar(255) NOT NULL,
caption varchar(255),
sortnr integer
);
CREATE temp TABLE tmp_viz_property_group_renderer
(
tid serial NOT NULL,
renderer_id integer NOT NULL,
property_group_id integer NOT NULL,
variable_name varchar(255)
);
CREATE temp TABLE tmp_viz_property
(
tid integer,
caption varchar(255),
prop_uniquename varchar(255),
prop_default varchar(255),
prop_unit varchar(255),
is_generic smallint DEFAULT 1,
static_values text,
is_mandatory smallint DEFAULT 0,
input_type_id integer DEFAULT 1,
input_type_uniquename varchar(255),
property_group_id integer,
property_group_uniquename varchar(255),
explanation text,
sortnr integer,
range_from integer,
range_to integer,
prop_value_type varchar(255) DEFAULT 'string'::character varying,
variable_name varchar(255),
is_general smallint
);
</#macro>
<#macro drop_temp_tables>
drop table tmp_viz_type;
drop table tmp_viz_property_group;
drop table tmp_viz_property;
drop table tmp_viz_type_property;
drop table tmp_viz_property_renderer;
drop table tmp_viz_property_group_renderer;
</#macro>
<#macro fill_viz_properties>
<#assign sortnr=0 />
<#foreach viz_prop in viz_properties>
<#assign sortnr=sortnr+100 />
insert into tmp_viz_property(tid,
caption,
prop_uniquename,
prop_default,
prop_unit,
is_generic,
static_values,
is_mandatory,
input_type_uniquename,
property_group_uniquename,
explanation,
sortnr,
range_from,
range_to,
prop_value_type,
variable_name,
is_general)
select P.tid,
'${viz_prop.caption}',
'${viz_prop.prop_uniquename}',
'${viz_prop.prop_default}',
'${viz_prop.prop_unit}',
${viz_prop.is_generic},
'${viz_prop.static_values}',
${viz_prop.is_mandatory},
'${viz_prop.input_type_uniquename}',
'${viz_prop.property_group_uniquename}',
'${viz_prop.explanation}',
${sortnr},
val('${viz_prop.range_from}'),
val('${viz_prop.range_to}'),
'${viz_prop.prop_value_type}',
<#if viz_prop.variable_name?exists>
'${viz_prop.variable_name}',
<#else>
'',
</#if>
0 as is_general
from xdummy left outer join viz_property P
on (P.prop_uniquename='${viz_prop.prop_uniquename}')
;
</#foreach>
<#assign sortnr=1000 />
<#foreach viz_prop in viz_type_properties_general>
<#assign sortnr=sortnr+100 />
insert into tmp_viz_property(tid,
caption,
prop_uniquename,
prop_default,
prop_unit,
is_generic,
static_values,
is_mandatory,
input_type_uniquename,
property_group_uniquename,
explanation,
sortnr,
range_from,
range_to,
prop_value_type,
variable_name,
is_general)
select P.tid,
'${viz_prop.caption}',
'${viz_prop.prop_uniquename}',
'${viz_prop.prop_default}',
'${viz_prop.prop_unit}',
${viz_prop.is_generic},
'${viz_prop.static_values}',
${viz_prop.is_mandatory},
'${viz_prop.input_type_uniquename}',
'${viz_prop.property_group_uniquename}',
'${viz_prop.explanation}',
${sortnr},
val('${viz_prop.range_from}'),
val('${viz_prop.range_to}'),
'${viz_prop.prop_value_type}',
<#if viz_prop.variable_name?exists>
'${viz_prop.variable_name}',
<#else>
'',
</#if>
1 as is_general
from xdummy left outer join viz_property P
on (P.prop_uniquename='${viz_prop.prop_uniquename}')
;
</#foreach>
update tmp_viz_property set input_type_id=T.tid
from viz_property_input_type T
where T.uniquename=tmp_viz_property.input_type_uniquename;
select 'Warnung: Property ohne input_type: ' || prop_uniquename
from tmp_viz_property
where input_type_id is null;
update tmp_viz_property set property_group_id=T.tid
from viz_property_group T
where T.uniquename=tmp_viz_property.property_group_uniquename;
select 'Warnung: Property ohne property_group: ' || prop_uniquename
from tmp_viz_property
where property_group_id is null;
--neue Datensätze:
insert into viz_property(
caption,
prop_uniquename,
prop_default,
prop_unit,
is_generic,
static_values,
is_mandatory,
input_type_id,
property_group_id,
explanation,
sortnr,
range_from,
range_to,
prop_value_type)
select
caption,
prop_uniquename,
prop_default,
prop_unit,
is_generic,
static_values,
is_mandatory,
input_type_id,
property_group_id,
explanation,
sortnr,
range_from,
range_to,
prop_value_type
from tmp_viz_property P
where P.tid is null;
update viz_property
set caption=T.caption,
--prop_uniquename,
prop_default=T.prop_default,
prop_unit=T.prop_unit,
is_generic=T.is_generic,
static_values=T.static_values,
is_mandatory=T.is_mandatory,
input_type_id=T.input_type_id,
property_group_id=T.property_group_id,
explanation=T.explanation,
sortnr=T.sortnr,
range_from=T.range_from,
range_to=T.range_to,
prop_value_type=T.prop_value_type
from tmp_viz_property T
where T.tid=viz_property.tid
and viz_property.tid in (select T.tid from tmp_viz_property T);
--renderer:
delete from viz_property_renderer
where (renderer_id, property_id)
in (select ${renderer_plot_id},P.tid
from tmp_viz_property P);
delete from viz_property_renderer
where (renderer_id, property_id)
in (select ${renderer_plot_id},P.tid
from tmp_viz_property P);
insert into viz_property_renderer(
renderer_id,
property_id,
variable_name)
select ${renderer_plot_id},
P.tid,
case when P.variable_name !='' then P.variable_name else P.prop_uniquename end
from tmp_viz_property P;
</#macro>

77
test/webapps_superx/test_viz/stud_zeitreihe_plot.html

@ -2322,7 +2322,7 @@ vizTypeProperties.push(newVizTypeProperty);
</style></head> </style></head>
<body class="has-navbar-fixed-top" onload="document.getElementById('progressbar').style.display='none';tableonload();initThemenbaumJs();"> <body class="has-navbar-fixed-top" onload="">
<div xmlns="http://www.w3.org/1999/xhtml" xmlns:sx="http://memtext.de" id="nd_navi_top"> <div xmlns="http://www.w3.org/1999/xhtml" xmlns:sx="http://memtext.de" id="nd_navi_top">
<nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation"> <nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation">
<div class="navbar-brand"><a class="navbar-item" target="_self" href="http://www.superx-projekt.de/"><img src="../images/sxlogo_transpar.png" alt="Zur Startseite der Institution" title="Zur Startseite" height="30px"></a><a class="navbar-item" href="http://www.superx-projekt.de/doku/kern_modul/benutzer/">Muster-Hochschule</a><div class="navbar-item is-hoverable"><button class="closebutton" title="Menü" onclick="toggleNavpanelFrame(this);"></button></div> <div class="navbar-brand"><a class="navbar-item" target="_self" href="http://www.superx-projekt.de/"><img src="../images/sxlogo_transpar.png" alt="Zur Startseite der Institution" title="Zur Startseite" height="30px"></a><a class="navbar-item" href="http://www.superx-projekt.de/doku/kern_modul/benutzer/">Muster-Hochschule</a><div class="navbar-item is-hoverable"><button class="closebutton" title="Menü" onclick="toggleNavpanelFrame(this);"></button></div>
@ -2590,8 +2590,72 @@ rs[0].push(new dataRow_0(16,'WiSe 2016/2017',21,21,100.00,20,95.24,'',5,23.81,5,
</div> </div>
<div class="columns"> <div class="columns">
<div class="column is-four-fifth"> <div class="column is-four-fifth">
<script type="text/javascript">
<script type="text/javascript">
function plot_it3(targetDiv)
{
var plotcode=document.getElementById("plotcode").value;
console.log(plotcode);
plotcode=plotcode.replace(/\n/g,' ');
var plotcodeObj=JSON.parse(plotcode);
var svgPlot=Plot.plot(plotcodeObj);
document.getElementById(targetDiv).innerHTML="";
document.getElementById(targetDiv).appendChild(svgPlot);
}
function plot_it(targetDiv) function plot_it(targetDiv)
{
var chartOptions={"caption":"Studierende nach Erst- und Neueinschreibung (Zeitreihe)",
"height":450,
"width":650,
"marginLeft":100,
"style":{"backgroundColor":"whitesmoke"},
"y":{"line":true},
"x":{"line":true,
"type":"band"},
"color":"blue",
"marks":[
Plot.barY ( rs[0],{"x":"eintrag","sort":"rownr","y":"gesamt","fill":"green","stroke":"orange"}),
Plot.line ( rs[0],{"x":"eintrag","sort":"rownr","y":"ges_1fs","stroke":"red"}),
Plot.line ( rs[0],{"x":"eintrag","sort":"rownr","y":"ges_1hs","stroke":"blue"})
]
}
chartOptions={"caption":"Studierende nach Erst- und Neueinschreibung (Zeitreihe)",
"height":450,
"width":650,
"marginLeft":100,
"style":{"backgroundColor":"whitesmoke"},
"y":{"line":true},
"x":{"line":true,
"type":"band"},
"color":"blue",
"marks":[
Plot.barY ( rs[0], {
"x":"eintrag",
"y":"gesamt",
"fill":"green",
"stroke":"orange",
channels: {sort1: {value: "rownr"}},
sort: {x: "sort1"} }),
Plot.line ( rs[0], {
"x":"eintrag",
"y":"ges_1fs",
"fill":"green",
"stroke":"red",
"strokeDasharray":[10,5],
channels: {sort1: {value: "rownr"}},
sort: {x: "sort1"} })
]
}
var svgPlot=Plot.plot(chartOptions);
document.getElementById(targetDiv).innerHTML="";
document.getElementById(targetDiv).appendChild(svgPlot);
}
function plot_it2(targetDiv)
{ {
var optionsString=""; var optionsString="";
optionsString+="{\"caption\":\"Studierende nach Erst- und Neueinschreibung (Zeitreihe)\",\"height\":450,\"width\":650,\"marginLeft\":100,\"style\":{\"backgroundColor\":\"whitesmoke\"},"; optionsString+="{\"caption\":\"Studierende nach Erst- und Neueinschreibung (Zeitreihe)\",\"height\":450,\"width\":650,\"marginLeft\":100,\"style\":{\"backgroundColor\":\"whitesmoke\"},";
@ -2610,14 +2674,16 @@ function plot_it(targetDiv)
var markOptions=JSON.parse(markOptionsStr); var markOptions=JSON.parse(markOptionsStr);
plotMark=Plot.barY(rs[0],markOptions); plotMark=Plot.barY(rs[0],markOptions);
marksArray[0]=plotMark; marksArray[0]=plotMark;
//Now line chart 1 console.log("OO"+markOptionsStr);
//Now line chart 1
var markOptionsStr="{\"x\":\"eintrag\",\"sort\":\"eintrag\",\"y\":\"ges_1fs\""; var markOptionsStr="{\"x\":\"eintrag\",\"sort\":\"eintrag\",\"y\":\"ges_1fs\"";
markOptionsStr+=",\"stroke\":\"red\""; markOptionsStr+=",\"stroke\":\"red\"";
markOptionsStr+="}"; markOptionsStr+="}";
markOptions=JSON.parse(markOptionsStr); markOptions=JSON.parse(markOptionsStr);
plotMark=Plot.line(rs[0],markOptions); plotMark=Plot.line(rs[0],markOptions);
marksArray[1]=plotMark; marksArray[1]=plotMark;
console.log("OO"+markOptionsStr);
//Now line chart 2 //Now line chart 2
var markOptionsStr="{\"x\":\"eintrag\",\"sort\":\"eintrag\",\"y\":\"ges_1hs\""; var markOptionsStr="{\"x\":\"eintrag\",\"sort\":\"eintrag\",\"y\":\"ges_1hs\"";
markOptionsStr+=",\"stroke\":\"blue\""; markOptionsStr+=",\"stroke\":\"blue\"";
@ -2628,12 +2694,13 @@ function plot_it(targetDiv)
chartOptions["marks"].push(marksArray); chartOptions["marks"].push(marksArray);
//optionsString+=" }"; //close tag //optionsString+=" }"; //close tag
console.log("OO"+markOptionsStr);
var svgPlot=Plot.plot(chartOptions); var svgPlot=Plot.plot(chartOptions);
document.getElementById(targetDiv).innerHTML=""; document.getElementById(targetDiv).innerHTML="";
document.getElementById(targetDiv).appendChild(svgPlot); document.getElementById(targetDiv).appendChild(svgPlot);
} }
</script> </script>
<a onClick="plot_it('chartDiv');">GO</a> <a onClick="plot_it('chartDiv');">GO</a>
</div> </div>
<div class="column"> <div class="column">

Loading…
Cancel
Save