giuliomoro@0
|
1 /*
|
giuliomoro@0
|
2 * Analysis script for WAET
|
giuliomoro@0
|
3 */
|
giuliomoro@0
|
4
|
giuliomoro@0
|
5 var chartContext;
|
giuliomoro@0
|
6 window.onload = function() {
|
giuliomoro@0
|
7 // Load the Visualization API and the corechart package.
|
giuliomoro@0
|
8 google.charts.load('current', {'packages':['corechart']});
|
giuliomoro@0
|
9 chartContext = new Chart();
|
giuliomoro@0
|
10 }
|
giuliomoro@0
|
11
|
giuliomoro@0
|
12 function arrayMean(values) {
|
giuliomoro@0
|
13 var mean = 0;
|
giuliomoro@0
|
14 for (var value of values) {
|
giuliomoro@0
|
15 mean += value;
|
giuliomoro@0
|
16 }
|
giuliomoro@0
|
17 mean /= values.length;
|
giuliomoro@0
|
18 return mean;
|
giuliomoro@0
|
19 }
|
giuliomoro@0
|
20
|
giuliomoro@0
|
21 function percentile(values, n) {
|
giuliomoro@0
|
22 values.sort( function(a,b) {return a - b;} );
|
giuliomoro@0
|
23 // get ordinal rank
|
giuliomoro@0
|
24 var rank = Math.min(Math.floor(values.length*n/100), values.length-1);
|
giuliomoro@0
|
25 return values[rank];
|
giuliomoro@0
|
26 }
|
giuliomoro@0
|
27
|
giuliomoro@0
|
28 function arrayMin(array) {
|
giuliomoro@0
|
29 // Return the minimum value of an array
|
giuliomoro@0
|
30 var min = array[0];
|
giuliomoro@0
|
31 for (var value of array) {
|
giuliomoro@0
|
32 if (value < min) {
|
giuliomoro@0
|
33 min = value;
|
giuliomoro@0
|
34 }
|
giuliomoro@0
|
35 }
|
giuliomoro@0
|
36 return min;
|
giuliomoro@0
|
37 }
|
giuliomoro@0
|
38
|
giuliomoro@0
|
39 function arrayMax(array) {
|
giuliomoro@0
|
40 // Return the minimum value of an array
|
giuliomoro@0
|
41 var max = array[0];
|
giuliomoro@0
|
42 for (var value of array) {
|
giuliomoro@0
|
43 if (value > max) {
|
giuliomoro@0
|
44 max = value;
|
giuliomoro@0
|
45 }
|
giuliomoro@0
|
46 }
|
giuliomoro@0
|
47 return max;
|
giuliomoro@0
|
48 }
|
giuliomoro@0
|
49
|
giuliomoro@0
|
50 function arrayHistogram(values,steps,min,max) {
|
giuliomoro@0
|
51 if (steps == undefined) {
|
giuliomoro@0
|
52 steps = 0.25;
|
giuliomoro@0
|
53 console.log("Warning: arrayHistogram called without steps size set, default to 0.25");
|
giuliomoro@0
|
54 }
|
giuliomoro@0
|
55 if (min == undefined) {min = arrayMin(values);}
|
giuliomoro@0
|
56 if (max == undefined) {max = arrayMax(values);}
|
giuliomoro@0
|
57 var histogram = [];
|
giuliomoro@0
|
58 var index = min;
|
giuliomoro@0
|
59 while(index < max) {
|
giuliomoro@0
|
60 histogram.push({
|
giuliomoro@0
|
61 marker: index,
|
giuliomoro@0
|
62 lt: index,
|
giuliomoro@0
|
63 rt: index+steps,
|
giuliomoro@0
|
64 count: 0
|
giuliomoro@0
|
65 });
|
giuliomoro@0
|
66 index += steps;
|
giuliomoro@0
|
67 }
|
giuliomoro@0
|
68 for (var value of values) {
|
giuliomoro@0
|
69 for (var entry of histogram) {
|
giuliomoro@0
|
70 if (value >= entry.lt && value <= entry.rt) {
|
giuliomoro@0
|
71 entry.count++;
|
giuliomoro@0
|
72 break;
|
giuliomoro@0
|
73 }
|
giuliomoro@0
|
74 }
|
giuliomoro@0
|
75 }
|
giuliomoro@0
|
76 return histogram;
|
giuliomoro@0
|
77 }
|
giuliomoro@0
|
78
|
giuliomoro@0
|
79 function Chart() {
|
giuliomoro@0
|
80 this.valueData = null;
|
giuliomoro@0
|
81 this.commentData = null;
|
giuliomoro@0
|
82 this.loadStatus = 0;
|
giuliomoro@0
|
83 this.charts = [];
|
giuliomoro@0
|
84
|
giuliomoro@0
|
85 var XMLHttp = new XMLHttpRequest();
|
giuliomoro@0
|
86 XMLHttp.parent = this;
|
giuliomoro@0
|
87 XMLHttp.open("GET","../scripts/score_parser.php?format=JSON",true);
|
giuliomoro@0
|
88 XMLHttp.onload = function() {
|
giuliomoro@0
|
89 // Now we have the JSON data, extract
|
giuliomoro@0
|
90 this.parent.valueData = JSON.parse(this.responseText);
|
giuliomoro@0
|
91 this.parent.loadStatus++;
|
giuliomoro@0
|
92 }
|
giuliomoro@0
|
93 XMLHttp.send();
|
giuliomoro@0
|
94 var XMLHttp2 = new XMLHttpRequest();
|
giuliomoro@0
|
95 XMLHttp2.parent = this;
|
giuliomoro@0
|
96 XMLHttp2.open("GET","../scripts/comment_parser.php?format=JSON",true);
|
giuliomoro@0
|
97 XMLHttp2.onload = function() {
|
giuliomoro@0
|
98 // Now we have the JSON data, extract
|
giuliomoro@0
|
99 this.parent.commentData = JSON.parse(this.responseText);
|
giuliomoro@0
|
100 this.parent.loadStatus++;
|
giuliomoro@0
|
101 }
|
giuliomoro@0
|
102 XMLHttp2.send();
|
giuliomoro@0
|
103
|
giuliomoro@0
|
104 this.chartObject = function(name) {
|
giuliomoro@0
|
105 // Create the charting object
|
giuliomoro@0
|
106 this.name = name;
|
giuliomoro@0
|
107 this.root = document.createElement("div");
|
giuliomoro@0
|
108 this.root.className = "chart-holder";
|
giuliomoro@0
|
109 this.root.setAttribute("name",name);
|
giuliomoro@0
|
110 this.chartDOM = document.createElement("div");
|
giuliomoro@0
|
111 this.tableDOM = document.createElement("div");
|
giuliomoro@0
|
112 this.latexDOM = document.createElement("div");
|
giuliomoro@0
|
113 this.downloadDOM = document.createElement("div");
|
giuliomoro@0
|
114 this.chart = undefined;
|
giuliomoro@0
|
115 this.data = new google.visualization.DataTable();
|
giuliomoro@0
|
116 this.options = {};
|
giuliomoro@0
|
117 this.print = document.createElement("button");
|
giuliomoro@0
|
118 this.sortDataButton = document.createElement("button");
|
giuliomoro@0
|
119 this.sortDataButton.textContent = "Sort by Data";
|
giuliomoro@0
|
120 this.sortDataButton.addEventListener("click",this);
|
giuliomoro@0
|
121 this.sortDataButton.setAttribute("name","sort-data");
|
giuliomoro@0
|
122 this.sortNameButton = document.createElement("button");
|
giuliomoro@0
|
123 this.sortNameButton.textContent = "Sort by Name";
|
giuliomoro@0
|
124 this.sortNameButton.addEventListener("click",this);
|
giuliomoro@0
|
125 this.sortNameButton.setAttribute("name","sort-name");
|
giuliomoro@0
|
126 this.draw = function() {
|
giuliomoro@0
|
127 if (this.chart == undefined) {return;}
|
giuliomoro@0
|
128 this.tableDOM.innerHTML = null;
|
giuliomoro@0
|
129 this.latexDOM.innerHTML = null;
|
giuliomoro@0
|
130 this.buildTable();
|
giuliomoro@0
|
131 this.writeLatex();
|
giuliomoro@0
|
132 this.chart.draw(this.data,this.options);
|
giuliomoro@0
|
133 }
|
giuliomoro@0
|
134 this.sortData = function() {
|
giuliomoro@0
|
135
|
giuliomoro@0
|
136 var map = this.data.Jf.map(function(el,i){
|
giuliomoro@0
|
137 return {index: i, value: el.c[1].v};
|
giuliomoro@0
|
138 });
|
giuliomoro@0
|
139
|
giuliomoro@0
|
140 map.sort(function(a,b){
|
giuliomoro@0
|
141 if (a.value > b.value) {return -1;}
|
giuliomoro@0
|
142 if (a.value < b.value) {return 1;}
|
giuliomoro@0
|
143 return 0;
|
giuliomoro@0
|
144 })
|
giuliomoro@0
|
145
|
giuliomoro@0
|
146 var Jf = [];
|
giuliomoro@0
|
147 var cc = [];
|
giuliomoro@0
|
148 for (var i=0; i<map.length; i++) {
|
giuliomoro@0
|
149 Jf.push(this.data.Jf[map[i].index]);
|
giuliomoro@0
|
150 cc.push(this.data.cc[map[i].index]);
|
giuliomoro@0
|
151 }
|
giuliomoro@0
|
152 this.data.Jf = Jf;
|
giuliomoro@0
|
153 this.data.cc = cc;
|
giuliomoro@0
|
154 }
|
giuliomoro@0
|
155 this.sortName = function() {
|
giuliomoro@0
|
156 var map = this.data.Jf.map(function(el,i){
|
giuliomoro@0
|
157 return {index: i, value: el.c[0].v};
|
giuliomoro@0
|
158 });
|
giuliomoro@0
|
159
|
giuliomoro@0
|
160 map.sort(function(a,b){
|
giuliomoro@0
|
161 if (a.value < b.value) {return -1;}
|
giuliomoro@0
|
162 if (a.value > b.value) {return 1;}
|
giuliomoro@0
|
163 return 0;
|
giuliomoro@0
|
164 })
|
giuliomoro@0
|
165
|
giuliomoro@0
|
166 var Jf = [];
|
giuliomoro@0
|
167 var cc = [];
|
giuliomoro@0
|
168 for (var i=0; i<map.length; i++) {
|
giuliomoro@0
|
169 Jf.push(this.data.Jf[map[i].index]);
|
giuliomoro@0
|
170 cc.push(this.data.cc[map[i].index]);
|
giuliomoro@0
|
171 }
|
giuliomoro@0
|
172 this.data.Jf = Jf;
|
giuliomoro@0
|
173 this.data.cc = cc;
|
giuliomoro@0
|
174 }
|
giuliomoro@0
|
175 this.handleEvent = function() {
|
giuliomoro@0
|
176 // Only used to handle the chart.event.addListener(this,'ready') callback
|
giuliomoro@0
|
177 switch(event.currentTarget.getAttribute("name"))
|
giuliomoro@0
|
178 {
|
giuliomoro@0
|
179 case "download":
|
giuliomoro@0
|
180 window.open(this.chart.getImageURI());
|
giuliomoro@0
|
181 break;
|
giuliomoro@0
|
182 case "sort-data":
|
giuliomoro@0
|
183 this.sortData();
|
giuliomoro@0
|
184 this.draw();
|
giuliomoro@0
|
185 break;
|
giuliomoro@0
|
186 case "sort-name":
|
giuliomoro@0
|
187 this.sortName();
|
giuliomoro@0
|
188 this.draw();
|
giuliomoro@0
|
189 break;
|
giuliomoro@0
|
190 }
|
giuliomoro@0
|
191 }
|
giuliomoro@0
|
192
|
giuliomoro@0
|
193 this.root.appendChild(this.chartDOM);
|
giuliomoro@0
|
194 this.root.appendChild(this.tableDOM);
|
giuliomoro@0
|
195 this.root.appendChild(this.latexDOM);
|
giuliomoro@0
|
196 this.root.appendChild(this.sortDataButton);
|
giuliomoro@0
|
197 this.root.appendChild(this.sortNameButton);
|
giuliomoro@0
|
198 this.root.appendChild(this.print);
|
giuliomoro@0
|
199 this.print.textContent = "Download";
|
giuliomoro@0
|
200 this.print.setAttribute("name","download");
|
giuliomoro@0
|
201 this.print.addEventListener("click",this);
|
giuliomoro@0
|
202 this.root.appendChild(this.downloadDOM);
|
giuliomoro@0
|
203 this.buildTable = function() {
|
giuliomoro@0
|
204 var table = document.createElement("table");
|
giuliomoro@0
|
205 table.border = "1";
|
giuliomoro@0
|
206 for (var rowIndex=0; rowIndex<this.data.If.length; rowIndex++) {
|
giuliomoro@0
|
207 var row = document.createElement("tr");
|
giuliomoro@0
|
208 table.appendChild(row);
|
giuliomoro@0
|
209 var rowTitle = document.createElement("td");
|
giuliomoro@0
|
210 rowTitle.textContent = this.data.If[rowIndex].label;
|
giuliomoro@0
|
211 row.appendChild(rowTitle);
|
giuliomoro@0
|
212 for (var cIndex=0; cIndex<this.data.cc.length; cIndex++) {
|
giuliomoro@0
|
213 var column = document.createElement("td");
|
giuliomoro@0
|
214 column.textContent = this.data.cc[cIndex][rowIndex].tf;
|
giuliomoro@0
|
215 row.appendChild(column);
|
giuliomoro@0
|
216 }
|
giuliomoro@0
|
217 }
|
giuliomoro@0
|
218 this.tableDOM.appendChild(table);
|
giuliomoro@0
|
219 };
|
giuliomoro@0
|
220 this.writeLatex = function() {
|
giuliomoro@0
|
221 var root = document.createElement("div");
|
giuliomoro@0
|
222 root.className = "code";
|
giuliomoro@0
|
223 var holder = document.createElement("pre");
|
giuliomoro@0
|
224 // Table start
|
giuliomoro@0
|
225 var start = document.createElement("p");
|
giuliomoro@0
|
226 start.textContent = "\\" + "begin{tabular}{|l|";
|
giuliomoro@0
|
227 holder.appendChild(start);
|
giuliomoro@0
|
228 for (var i=0; i<this.data.cc.length; i++) {
|
giuliomoro@0
|
229 start.textContent = start.textContent+"c|";
|
giuliomoro@0
|
230 }
|
giuliomoro@0
|
231 start.textContent = start.textContent.concat("}");
|
giuliomoro@0
|
232 // Now write the rows:
|
giuliomoro@0
|
233 for (var rIndex=0; rIndex<this.data.If.length; rIndex++) {
|
giuliomoro@0
|
234 var row = document.createElement("p");
|
giuliomoro@0
|
235 row.textContent = this.data.If[rIndex].label.concat(" & ");
|
giuliomoro@0
|
236 for (var cIndex=0; cIndex<this.data.cc.length; cIndex++) {
|
giuliomoro@0
|
237 row.textContent = row.textContent.concat(this.data.cc[cIndex][rIndex].tf);
|
giuliomoro@0
|
238 if (cIndex < this.data.cc.length-1) {
|
giuliomoro@0
|
239 row.textContent = row.textContent.concat(" & ");
|
giuliomoro@0
|
240 }
|
giuliomoro@0
|
241 }
|
giuliomoro@0
|
242 holder.appendChild(row);
|
giuliomoro@0
|
243 }
|
giuliomoro@0
|
244 // Table end
|
giuliomoro@0
|
245 var end = document.createElement("p");
|
giuliomoro@0
|
246 end.textContent = "\\" + "end{tabular}";
|
giuliomoro@0
|
247 holder.appendChild(end);
|
giuliomoro@0
|
248 root.appendChild(holder);
|
giuliomoro@0
|
249 this.latexDOM.appendChild(root);
|
giuliomoro@0
|
250 }
|
giuliomoro@0
|
251 }
|
giuliomoro@0
|
252
|
giuliomoro@0
|
253 this.clear = function() {
|
giuliomoro@0
|
254 var inject = document.getElementById("test-pages");
|
giuliomoro@0
|
255 for (var chart of this.charts) {
|
giuliomoro@0
|
256 inject.removeChild(chart.root);
|
giuliomoro@0
|
257 }
|
giuliomoro@0
|
258 this.charts = [];
|
giuliomoro@0
|
259 }
|
giuliomoro@0
|
260
|
giuliomoro@0
|
261 this.drawTestMean = function() {
|
giuliomoro@0
|
262 // This draws one bargraph per axis with every test element on
|
giuliomoro@0
|
263 if (this.valueData == null) {
|
giuliomoro@0
|
264 console.log("Error - Data not loaded");
|
giuliomoro@0
|
265 return;
|
giuliomoro@0
|
266 }
|
giuliomoro@0
|
267 var chartList = [];
|
giuliomoro@0
|
268
|
giuliomoro@0
|
269 // Create the data table
|
giuliomoro@0
|
270 for (var page of this.valueData.pages) {
|
giuliomoro@0
|
271 for (var element of page.elements) {
|
giuliomoro@0
|
272 for (var axis of element.axis) {
|
giuliomoro@0
|
273 // Find the axis
|
giuliomoro@0
|
274 var axisChart = chartList.find(function(element,index,array){
|
giuliomoro@0
|
275 if (element.name == this) {return true;} else {return false;}
|
giuliomoro@0
|
276 },"mean-test-"+axis.id);
|
giuliomoro@0
|
277 if (axisChart == null) {
|
giuliomoro@0
|
278 axisChart = new this.chartObject("mean-test-"+axis.id);
|
giuliomoro@0
|
279 axisChart.options = {
|
giuliomoro@0
|
280 'title':'Mean of axis: '+axis.name,
|
giuliomoro@0
|
281 'width':window.innerWidth*0.9,
|
giuliomoro@0
|
282 'height':(window.innerWidth*0.9)/1.77
|
giuliomoro@0
|
283 }
|
giuliomoro@0
|
284 axisChart.data.addColumn('string','id');
|
giuliomoro@0
|
285 axisChart.data.addColumn('number',axis.name);
|
giuliomoro@0
|
286 chartList.push(axisChart);
|
giuliomoro@0
|
287 document.getElementById("test-pages").appendChild(axisChart.root);
|
giuliomoro@0
|
288 }
|
giuliomoro@0
|
289 var mean = arrayMean(axis.values);
|
giuliomoro@0
|
290 axisChart.data.addRow([element.id,mean]);
|
giuliomoro@0
|
291 }
|
giuliomoro@0
|
292 }
|
giuliomoro@0
|
293 }
|
giuliomoro@0
|
294
|
giuliomoro@0
|
295 // Build and push charts
|
giuliomoro@0
|
296 for (var chart of chartList) {
|
giuliomoro@0
|
297 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
|
giuliomoro@0
|
298 chart.chart.draw(chart.data,chart.options);
|
giuliomoro@0
|
299 chart.buildTable();
|
giuliomoro@0
|
300 chart.writeLatex();
|
giuliomoro@0
|
301 this.charts.push(chart);
|
giuliomoro@0
|
302 }
|
giuliomoro@0
|
303 }
|
giuliomoro@0
|
304
|
giuliomoro@0
|
305 this.drawPageMean = function() {
|
giuliomoro@0
|
306 // First we must get the value data
|
giuliomoro@0
|
307 if (this.valueData == null) {
|
giuliomoro@0
|
308 console.log("Error - Data not loaded");
|
giuliomoro@0
|
309 return;
|
giuliomoro@0
|
310 }
|
giuliomoro@0
|
311 // We create one plot per page
|
giuliomoro@0
|
312 for (var page of this.valueData.pages) {
|
giuliomoro@0
|
313
|
giuliomoro@0
|
314 // Create the chart resulting point
|
giuliomoro@0
|
315 var chart = new this.chartObject("mean-page-"+page.id);
|
giuliomoro@0
|
316 document.getElementById("test-pages").appendChild(chart.root);
|
giuliomoro@0
|
317
|
giuliomoro@0
|
318 // Create the data table
|
giuliomoro@0
|
319 chart.data.addColumn('string','id');
|
giuliomoro@0
|
320 // Get axis labels
|
giuliomoro@0
|
321 for (var axis of page.elements[0].axis) {
|
giuliomoro@0
|
322 chart.data.addColumn('number',axis.name);
|
giuliomoro@0
|
323 }
|
giuliomoro@0
|
324 var rows = []; // Rows is an array of tuples [col1, col2, col3 ... colN];
|
giuliomoro@0
|
325 for (var element of page.elements) {
|
giuliomoro@0
|
326 var entry = [element.id];
|
giuliomoro@0
|
327 for (var i=0; i<page.elements[0].axis.length; i++) {
|
giuliomoro@0
|
328 var mean =0;
|
giuliomoro@0
|
329 if (i < element.axis.length) {
|
giuliomoro@0
|
330 var axis = element.axis[i];
|
giuliomoro@0
|
331 mean = arrayMean(axis.values);
|
giuliomoro@0
|
332 }
|
giuliomoro@0
|
333 entry.push(mean);
|
giuliomoro@0
|
334 }
|
giuliomoro@0
|
335 rows.push(entry);
|
giuliomoro@0
|
336 }
|
giuliomoro@0
|
337 chart.data.addRows(rows);
|
giuliomoro@0
|
338 chart.options = {
|
giuliomoro@0
|
339 'title':'Mean of page: '+page.id,
|
giuliomoro@0
|
340 'width':800,
|
giuliomoro@0
|
341 'height':700
|
giuliomoro@0
|
342 }
|
giuliomoro@0
|
343 // Draw the chart
|
giuliomoro@0
|
344 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
|
giuliomoro@0
|
345 chart.chart.draw(chart.data,chart.options);
|
giuliomoro@0
|
346 chart.buildTable();
|
giuliomoro@0
|
347 chart.writeLatex();
|
giuliomoro@0
|
348 this.charts.push(chart);
|
giuliomoro@0
|
349 }
|
giuliomoro@0
|
350 }
|
giuliomoro@0
|
351
|
giuliomoro@0
|
352 this.drawElementHistogram = function() {
|
giuliomoro@0
|
353 // First we must get the value data
|
giuliomoro@0
|
354 if (this.valueData == null) {
|
giuliomoro@0
|
355 console.log("Error - Data not loaded");
|
giuliomoro@0
|
356 return;
|
giuliomoro@0
|
357 }
|
giuliomoro@0
|
358 // We create one plot per element, enjoy...
|
giuliomoro@0
|
359 for (var page of this.valueData.pages) {
|
giuliomoro@0
|
360 for (var element of page.elements) {
|
giuliomoro@0
|
361 // Build the chart object
|
giuliomoro@0
|
362 var chart = new this.chartObject("histogram-element-"+element.id);
|
giuliomoro@0
|
363 document.getElementById("test-pages").appendChild(chart.root);
|
giuliomoro@0
|
364 chart.data.addColumn('string','index');
|
giuliomoro@0
|
365 var histograms = [];
|
giuliomoro@0
|
366 for (var axis of element.axis) {
|
giuliomoro@0
|
367 chart.data.addColumn('number',axis.name);
|
giuliomoro@0
|
368 histograms.push(arrayHistogram(axis.values,0.125,0.0,1.0));
|
giuliomoro@0
|
369 }
|
giuliomoro@0
|
370 for (var axis of element.axis) {
|
giuliomoro@0
|
371 for (var i=0; i<histograms[0].length; i++)
|
giuliomoro@0
|
372 {
|
giuliomoro@0
|
373 var entry = [""+histograms[0][i].lt.toPrecision(2)+"-"+histograms[0][i].rt.toPrecision(3)]
|
giuliomoro@0
|
374 for (var histogram of histograms) {
|
giuliomoro@0
|
375 entry.push(histogram[i].count);
|
giuliomoro@0
|
376 }
|
giuliomoro@0
|
377 chart.data.addRow(entry);
|
giuliomoro@0
|
378 }
|
giuliomoro@0
|
379 }
|
giuliomoro@0
|
380 chart.options = {
|
giuliomoro@0
|
381 'title':'Histogram of element: '+element.id,
|
giuliomoro@0
|
382 'width':800,
|
giuliomoro@0
|
383 'height':700,
|
giuliomoro@0
|
384 'bar':{'groupWidth': '100%'}
|
giuliomoro@0
|
385 }
|
giuliomoro@0
|
386 // Draw the chart
|
giuliomoro@0
|
387 chart.chart = new google.visualization.ColumnChart(chart.chartDOM);
|
giuliomoro@0
|
388 chart.chart.draw(chart.data,chart.options);
|
giuliomoro@0
|
389 chart.buildTable();
|
giuliomoro@0
|
390 chart.writeLatex();
|
giuliomoro@0
|
391 this.charts.push(chart);
|
giuliomoro@0
|
392 }
|
giuliomoro@0
|
393 }
|
giuliomoro@0
|
394 }
|
giuliomoro@0
|
395 } |