Display objects with the same key in one row - javascript

I got this objects
{"key":["0114","1","2013"],"values":["279"]},
{"key":["0114","1","2014"],"values":["235"]},
{"key":["0114","1","2015"],"values":["258"]},
{"key":["0114","1","2016"],"values":["274"]},
{"key":["0114","1","2017"],"values":["293"]}
0114 is a county in sweden.
1 is symbolizes men
2013... is the years
values is the amount of men born in ex. 2013
I want to display them like this:
How it looks right now:
How i'm displaying rightnow :
<div class="tabellWrapper">
<table class="kommunerMainWrapper" >
<thead>
<tr>
<td >Kommun</td>
<th >Kön</th>
<th >2013</th>
<th >2014</th>
<th >2015</th>
<th >2016</th>
<th >2017</th>
</tr>
</thead>
<tbody class="kommunerWrapper" >
<template v-for="(data,index) in selectedLanData">
<tr v-if="data.key[1] ==='1'" :key="index">
<th class="kommunerItem kommun">{{data.key[0]}}</th>
<th class="kommunerItem sex" >Män</th>
<th class="kommunerItem numbers">{{data.values[0]}}</th>
<th class="kommunerItem numbers">{{data.key[2]}}</th>
</tr>
<tr v-else :key="index">
<th class="kommunerItem kommun">{{data.key[0]}}</th>
<th class="kommunerItem sex" >Kvinnor</th>
<th class="kommunerItem numbers">{{data.values[0]}}</th>
<th class="kommunerItem numbers">{{data.key[2]}}</th>
</tr>
</template>
</tbody>
</table>
</div>
</div>

I think you should parse your data array before. If it is a possibility for you, this could be the code:
var source = [
{"key":["0114","1","2013"],"values":["279"]},
{"key":["0114","1","2014"],"values":["235"]},
{"key":["0114","1","2015"],"values":["258"]},
{"key":["0114","1","2016"],"values":["274"]},
{"key":["0114","1","2017"],"values":["293"]}
];
var parsed = {};
for (var i=0; i<source.length; i++) {
var key = source[i].key;
if (!(source[i].key[0] in parsed)) {
parsed[source[i].key[0]] = {};
}
if (!(source[i].key[1] in parsed[source[i].key[0]])) {
parsed[source[i].key[0]][source[i].key[1]] = {};
}
if (!(source[i].key[2] in parsed[source[i].key[0]][source[i].key[1]])) {
parsed[source[i].key[0]][source[i].key[1]][source[i].key[2]] = 0;
}
parsed[source[i].key[0]][source[i].key[1]][source[i].key[2]] += parseInt(source[i].values);
}
console.log(parsed);

You can simply do it with the reduce function as so:
const data = [
{"key":["0114","1","2013"],"values":["279"]},
{"key":["0114","1","2014"],"values":["235"]},
{"key":["0114","1","2015"],"values":["258"]},
{"key":["0114","1","2016"],"values":["274"]},
{"key":["0114","1","2017"],"values":["293"]}
];
const tableRows = data.reduce((rows, value) => {
let currentRow = rows.find(row => row.region === value.key[0] && row.gender === value.key[1]);
if (!currentRow) {
currentRow = {region: value.key[0], gender: value.key[1]};
rows.push(currentRow);
}
currentRow[value.key[2]] = value.values[0];
return rows;
}, []);
console.log(tableRows);

Related

Sort date in dd/mm/yyyy format in html table using jquery function

I have an HTML table and one column is date values.How to sort the values in descending order in the first click and in ascending order in the second click while clicking on column heading Date
function getVal(elm, n) {
var v = $(elm).find('td').eq(n).text().toUpperCase();
var num = v.split(/ /)[0].replace(/[^\d]/g, '')
num = parseFloat(num);
if ($.isNumeric(num)) {
v = parseInt(num, 10);
}
return v;
}
var f = 1;
$(".table-sortable .column-head").find('span,img').click(function(event) {
event.preventDefault();
table = $(this).closest('table');
th = $(this).parent();
$(th).find('span,img').toggleClass('rotate');
f *= -1;
var n = th.prevAll().length;
console.log(n);
var rows = table.find('tbody tr').get();
rows.sort(function(a, b) {
var A = getVal(a, n);
var B = getVal(b, n);
if (A < B) {
return -1 * f;
}
if (A > B) {
return 1 * f;
}
return 0;
});
$.each(rows, function(index, row) {
table.children('tbody').append(row);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table-sortable">
<thead>
<tr>
<th scope="col" class="column-head"><span>Date</span></th>
</tr>
</thead>
<tbody class="table-body">
<tr class="table-row">
<td class="column-values">20/01/2015</td>
</tr>
<tr class="table-row">
<td class="column-values">20/02/2016</td>
</tr>
<tr class="table-row">
<td class="column-values">10/01/2017</td>
</tr>
<tr class="table-row">
<td class="column-values">08/01/2017</td>
</tr>
<tr class="table-row">
<td class="column-values">12/04/2013</td>
</tr>
<tr class="table-row">
<td class="column-values">12/03/2013</td>
</tr>
</tbody>
</table>
https://jsfiddle.net/bb4659av/
You can convert your date in YYYY/MM/DD format and then sort it using localeCompare.
function getVal(elm, n) {
var v = $(elm).find('td').eq(n).text().toUpperCase();
v = v.replace(/(..)\/(..)\/(....)/, '$3/$2/$1');
return v;
}
var f = 1;
$(".table-sortable .column-head").find('span,img').click(function(event) {
event.preventDefault();
table = $(this).closest('table');
th = $(this).parent();
$(th).find('span,img').toggleClass('rotate');
f *= -1;
var n = th.prevAll().length;
var rows = table.find('tbody tr').get();
rows.sort(function(a, b) {
var A = getVal(a, n);
var B = getVal(b, n);
return f * A.localeCompare(B);
});
$.each(rows, function(index, row) {
table.children('tbody').append(row);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="table-sortable">
<thead>
<tr>
<th scope="col" class="column-head"><span>Date</span></th>
</tr>
</thead>
<tbody class="table-body">
<tr class="table-row">
<td class="column-values">20/01/2015</td>
</tr>
<tr class="table-row">
<td class="column-values">20/02/2016</td>
</tr>
<tr class="table-row">
<td class="column-values">10/01/2017</td>
</tr>
<tr class="table-row">
<td class="column-values">08/01/2017</td>
</tr>
<tr class="table-row">
<td class="column-values">12/04/2013</td>
</tr>
<tr class="table-row">
<td class="column-values">12/03/2013</td>
</tr>
</tbody>
</table>
Just as a comparison, here's a version using POJS once you have a cell in the column to sort. I think it will be a lot more efficient that the jQuery alternative.
"Ascending order" is ambiguous to me, I guess you want the newest dates at the top. To reverse the order, just reverse the comparison in the sort function.
/* Given a table cell, find the parent table and sort the first tbody's
** rows by the given column as dates in format dd/mm/yyyy. Sorts most
** recent date to top, oldest to bottom.
*/
function sortAsDate(cell) {
var col = cell.cellIndex,
table = cell.parentNode.parentNode.parentNode,
tbody = table.tBodies[0],
formatter = row => row.cells[col].textContent.split(/\D/).reverse().join('');
Array.from(tbody.rows)
.sort((a, b) => formatter(a).localeCompare(formatter(b)))
.reduceRight((acc, row) => tbody.appendChild(row), null);
}
<table class="table-sortable">
<thead>
<tr>
<th scope="col" class="column-head"><span onclick="sortAsDate(this.parentNode)">Date</span></th>
</tr>
</thead>
<tbody class="table-body">
<tr class="table-row"><td class="column-values">20/01/2015</td></tr>
<tr class="table-row"><td class="column-values">20/02/2016</td></tr>
<tr class="table-row"><td class="column-values">10/01/2017</td></tr>
<tr class="table-row"><td class="column-values">08/01/2017</td></tr>
<tr class="table-row"><td class="column-values">12/04/2013</td></tr>
<tr class="table-row"><td class="column-values">12/03/2013</td></tr>
</tbody>
</table>

MVC Asp.net with javascript take table check values

I'm trying to post data to a Controller from an MVC View and I'm having problems. The code is as follows:
<div id="no-more-tables">
<table id="CarteraClients" style="width: 100%;">
<thead>
<tr>
<th scope="col" id="col1" width="55%">Cliente</th>
<th scope="col" id="col2">Semana 1 </th>
<th scope="col" id="col2">Semana 2 </th>
<th scope="col" id="col2">Semana 3 </th>
<th scope="col" id="col2">Semana 4 </th>
<th scope="col" id="col2">Semana 5 </th>
</tr>
</thead>
<tbody>
#{
if (Model.Count() == 0)
{
<tr>
<th colspan="4" class="error text-center">
<small class="error">No hay elementos coincidentes.</small></th>
</tr>
}
else
{
foreach (var item in Model)
{
<tr>
<td data-title="Razon Social">
#Html.DisplayFor(modelItem =>
item.razon_social)
</td>
<td data-title="Semana 1" id="Semana1"
class="row1">#Html.CheckBox("chkSemana1", false)</td>
<td data-title="Semana 2" id="Semana2"
class="row1">#Html.CheckBox("chkSemana2", false)</td>
<td data-title="Semana 3" id="Semana3"
class="row1">#Html.CheckBox("chkSemana3", false)</td>
<td data-title="Semana 4" id="Semana4"
class="row1">#Html.CheckBox("chkSemana4", false)</td>
<td data-title="Semana 5" id="Semana5"
class="row1">#Html.CheckBox("chkSemana5", false)</td>
</tr>
}
}
}
</tbody>
</table>
<button type="button" class="small" onclick="llenardata()"><img
src="~/Content/img/magnifying-glass-8x.png" alt="Buscar" width="16"
height="16" /> Guardar cartera</button>
</div>
The script that I'm using to generate the structure to send via json:
<script type="text/javascript">
function llenardata() {
var cant = 0;
var tabla = document.getElementById("CarteraClients");
var rowLength =
document.getElementById("CarteraClients").rows[0].cells.length;
var tablaresultados = [];
for (i = 0; i < tabla.rows.length; i++) {
var ocells = tabla.rows.item(i).cells;
var cellLength = ocells.length;
var cliente = ocells.item(0).innerText;
var semana1 = ocells.item(1).innerText;
var semana2 = ocells.item(2).innerText;
var semana3 = ocells.item(3).innerText;
var semana4 = ocells.item(4).innerText;
var semana5 = ocells.item(5).innerText;
tablaresultados.push(cliente);
//tablaresultados.push(semana1);
//tablaresultados.push(semana2);
//tablaresultados.push(semana3);
//tablaresultados.push(semana4);
//tablaresultados.push(semana5);
}
console.log(tablaresultados);
$.ajax({
url: url("IngresoProyeccion") + 'GuardarCarteraCliente',
data:
'IdUser=' + delegado +
'&Ano=' + anyos +
'&Mes=' + meses +
'&Oportunidad= Levantamiento de Oportunidades'+
'&Cartera='+tablaresultados,
dataType: 'json',
type: 'POST',
}).success(function (html) {
DesbloquearPantalla();
$("#divReporte").html(html);
//$("body").animate({ scrollTop: $(document).height() },
'fast');
});
}
</script>
But it doesn't take the values of the checkbox on semana1, semana2, semana3, semana4, semana5 in the var tablaresultados.
I need help to resolve this problem. Thanks.

dataTables.js not resizing properly. Table overflows window still

I am using dataTables.js from https://datatables.net/ I am also using their responsive extension , but I can not get the table to properly responsively resize. Any insight would be grand.
The table overflows the window.
If you expand it all the way out so all the columns are shown, it doesn't even start hiding columns until the 3rd column is off screen
I have created a jsfiddle with my code.
$(document).ready(function() {
// Setup - add a text input to each footer cell
$('#Table_Assets tfoot th').each(function() {
var title = $('#Table_Assets thead th').eq($(this).index()).text();
$(this).html('<input type="text" style="max-width:80px;" />');
});
// DataTable
var table = $('#Table_Assets').DataTable({
responsive: true,
"autoWidth": false,
"order": [
[13, "desc"]
],
initComplete: function() {
var r = $('#Table_Assets tfoot tr');
r.find('th').each(function() {
$(this).css('padding', 8);
});
$('#Table_Assets thead').append(r);
$('#search_0').css('text-align', 'center');
},
});
$('#Table_Assets').resize()
// Apply the search
table.columns().every(function() {
var that = this;
$('input', this.footer()).on('keyup change', function() {
that.search(this.value)
.draw();
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://cdn.datatables.net/1.10.6/css/jquery.dataTables.min.css" rel="stylesheet" />
<script src="https://cdn.datatables.net/1.10.6/js/jquery.dataTables.min.js" type="text/javascript"></script>
<link href="https://cdn.datatables.net/responsive/1.0.6/css/dataTables.responsive.css" rel="stylesheet">
<script src="https://cdn.datatables.net/responsive/1.0.6/js/dataTables.responsive.js" type="text/javascript"></script>
<div style="max-width:100%; margin-left:auto; margin-right:auto; background-color:#c4bcbc; border-radius:15px; padding:10px; color:black" class="center">
<table id="Table_Assets" class="outerroundedborder dt-responsive" style="width:auto; margin-bottom: 15px; margin-left:auto; margin-right:auto">
<thead>
<tr style="white-space:nowrap;">
<th scope="col">Name:</th>
<th scope="col">Type:</th>
<th scope="col">Manufacturer</th>
<th scope="col">Supplier</th>
<th scope="col">Quantity</th>
<th scope="col">Serial Number</th>
<th scope="col">Location:</th>
<th scope="col">Comments</th>
<th scope="col">Computer Name</th>
<th scope="col">Room Number</th>
<th scope="col">Active</th>
<th scope="col">Tech Fee</th>
<th scope="col">Specifications</th>
<th scope="col">Deploy Date</th>
<th scope="col">User</th>
<th scope="col">Department</th>
<th scope="col">Building</th>
<th scope="col">Tickets</th>
</tr>
</thead>
<tbody>
<tr>
<td style="width:auto;">Doom DOOM!</td>
<td>Laptop</td>
<td>HP</td>
<td>none</td>
<td>33</td>
<td>sdfg</td>
<td>sdfg</td>
<td>dfhgdfh</td>
<td>Nebulus</td>
<td>2345</td>
<td>True</td>
<td>True</td>
<td>Stuff from space</td>
<td>5/30/2015</td>
<td>Michaels | Joey</td>
<td>Staff</td>
<td></td>
<td>
<br />
<div class="grey">No tickets found</div>
</td>
</tr>
<tr>
<td style="width:auto;">Dr. Von Doom</td>
<td>Laptop</td>
<td>HP</td>
<td>none</td>
<td>0</td>
<td>123412341234</td>
<td>Dr. Doom's Lair</td>
<td></td>
<td>Spiderman</td>
<td>42</td>
<td>True</td>
<td></td>
<td>Spidey sense is tingling. ^_^</td>
<td>6/18/2015</td>
<td>Michaels | Joey</td>
<td>Staff</td>
<td>AIC Faculty</td>
<td>
<br />
<div class="grey">No tickets found</div>
</td>
</tr>
</tbody>
<tfoot>
<tr class="sortbottom">
<th scope="col">Name:</th>
<th scope="col">Type:</th>
<th scope="col">Manufacturer</th>
<th scope="col">Supplier</th>
<th scope="col">Quantity</th>
<th scope="col">Serial Number</th>
<th scope="col">Location:</th>
<th scope="col">Comments</th>
<th scope="col">Computer Name</th>
<th scope="col">Room Number</th>
<th scope="col">Active</th>
<th scope="col">Tech Fee</th>
<th scope="col">Specifications</th>
<th scope="col">Deploy Date</th>
<th scope="col">User</th>
<th scope="col">Department</th>
<th scope="col">Building</th>
<th scope="col">Tickets</th>
</tr>
</tfoot>
</table>
</div>
I have the same issue, I'm using the jquery DataTables 1.10.7 and the extension Responsive 1.0.6, I solved by adding a line in the "dataTables.responsive.js" in the _resize function, about line 560.
Add the next line at the end of the function:
$(dt.table().node()).removeAttr('style');
That should work.
The function most look like this:
_resize: function() {
var dt = this.s.dt;
var width = $(window).width();
var breakpoints = this.c.breakpoints;
var breakpoint = breakpoints[0].name;
var columns = this.s.columns;
var i, ien;
// Determine what breakpoint we are currently at
for (i = breakpoints.length - 1; i >= 0; i--) {
if (width <= breakpoints[i].width) {
breakpoint = breakpoints[i].name;
break;
}
}
// Show the columns for that break point
var columnsVis = this._columnsVisiblity(breakpoint);
// Set the class before the column visibility is changed so event
// listeners know what the state is. Need to determine if there are
// any columns that are not visible but can be shown
var collapsedClass = false;
for (i = 0, ien = columns.length; i < ien; i++) {
if (columnsVis[i] === false && !columns[i].never) {
collapsedClass = true;
break;
}
}
$(dt.table().node()).toggleClass('collapsed', collapsedClass);
dt.columns().eq(0).each(function(colIdx, i) {
dt.column(colIdx).visible(columnsVis[i]);
});
$(dt.table().node()).removeAttr('style');
},
Best regards.

Grid, Selecting Header_Id from one and Content values from another table and pushing "value with Id" in Array Jquery

what i have is a grid, that is formed with combination of two tables. One section contain Header contents and other values added by user. Below is problem statment.
I have a div inside which a table resides. That make Header of the grid.
Another div having table in it. That contain rows for values.
Demonstration:
<div class="k-grid-header-wrap">
<table role="grid" id="Header" cellspacing="0">
<thead>
<tr>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_47" data-title="Q1">Q1</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_48" data-title="Q2">Q2</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_10048" data-title="Q3">Q3</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_10049" data-title="Q4">Q4</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_10050" data-title="Q5">Q5</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_10051" data-title="Q7">Q7</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_10052" data-title="Q8">Q8</th>
<th class="k-header" role="columnheader" data-field="ColumnID_20_17_10053" data-title="Q9">Q9</th>
<th class="k-header"></th>
</tr>
</thead>
</table>
</div>
<div style="height: 260px;" class="k-grid-content">
<table role="grid" id="tbl_1" cellspacing="0">
<tbody>
<tr class="" data-uid="a692c39b" role="row">
<td data-role="editable" class="" role="gridcell">1 </td>
<td data-role="editable" class="" role="gridcell">2</td>
<td data-role="editable" class="" role="gridcell">3</td>
<td data-role="editable" class="" role="gridcell">4</td>
<td data-role="editable" class="" role="gridcell">5</td>
<td data-role="editable" class="" role="gridcell">6</td>
<td data-role="editable" class="" role="gridcell">7</td>
<td data-role="editable" class="" role="gridcell">eight</td>
</tr>
</tbody>
</table>
</div>
Now what i want to do is against every row user enter in grid i want to push every grid cell values with ID to another table.
So forth what i have is:
function OnSave() {
var answerArray = [];
$("th[data-field*='_']").each(function () {
var Columnid = $(this).attr('data-field');
var Columntemp = Columnid.split('_');
var ColumnSection = Columntemp[1];
var ColumnQGroup = Columntemp[2];
var ColumnQuestion = Columntemp[3];
var ColumnRadiostatus = $(this).is(':checked');
var rowNum = $(this).parent().parent().index();
var ColumnValue;
$("#div1 table tbody tr").map(function (index, elem) {
// $('td', this).each(function () {
var tmp = $(this).find('td');
ColumnValue = $(tmp).val() || $(tmp).text();
if (!(ColumnValue instanceof Array))
{
ColumnValue = [ColumnValue];
}
answerArray.push(new clientAnswer(ColumnSection, ColumnQGroup, ColumnQuestion, ColumnRadiostatus, ColumnValue, rowNum));
//});
});
});
var serializedAnswers = Sys.Serialization.JavaScriptSerializer.serialize(answerArray);
PageMethods.UpdateAnswers(serializedAnswers, callBackUpdateAnswers);
}
function callBackUpdateAnswers(result) {
alert(result);
if (result == 'false') {
return false;
}
}
Which return whole row against every question.
Expected Output answerArray(20, 17, Q1, 1);
What's Now: answerArray(20, 17, Q1, 123456789);
Any Help would be appreciated. Regards
Following is solution for your issue:
function OnSave() {
var answerArray = [];
$("#Header th[data-field*='_']").each(function () {
var Columnid = $(this).attr('data-field');
var Columntemp = Columnid.split('_');
var ColumnSection = Columntemp[1];
var ColumnQGroup = Columntemp[2];
var ColumnQuestion = Columntemp[3];
var ColumnRadiostatus = $(this).is(':checked');
var rowNum = $(this).parent().parent().index();
var ColumnValue;
ColumnValue = $('#tbl_1 tr:eq(' + $(this).parent().index() + ') td:eq(' + $(this).index() + ')').text();
//alert("columnValue : " + ColumnValue);
if (!(ColumnValue instanceof Array)) {
ColumnValue = [ColumnValue];
}
answerArray.push(new clientAnswer(ColumnSection, ColumnQGroup, ColumnQuestion, ColumnRadiostatus, ColumnValue, rowNum));
});
var serializedAnswers = Sys.Serialization.JavaScriptSerializer.serialize(answerArray);
PageMethods.UpdateAnswers(serializedAnswers, callBackUpdateAnswers);
}
See Demo Here:
View Demo

How can I duplicate this in jQuery?

I have this code:
/* Modify the footer row to match what we want */
var nCells = nRow.getElementsByTagName('th');
nCells[1].innerHTML = iPageCPSV;
nCells[2].innerHTML = iPageCGV;
nCells[3].innerHTML = iPagePPSV;
nCells[4].innerHTML = iPagePGV;
It works just fine as it is. However I have added another <tr> into the section now. And I am having trouble figureing out how to populate the <th> in the second <tr>
<tfoot>
<tr style="background-color: #DDDDDD;">
<th align="right" colspan="6">
Page Total:
</th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
</tr>
<tr style="background-color: #DDDDDD;">
<th align="right" colspan="6">
Downline Total:
</th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
<th align="left"></th>
</tr>
</tfoot>
Before I added the second <tr> with more <th> everything worked. It still works, I just don't know how to populate the data into the second row. Can anyone help me modify the existing JavaScript or tell me how to duplicate it into jQuery?
Without jQuery...
var foot = nRow.getElementsByTagName('tfoot')[0];
foot.rows[0].cells[1].innerHTML = iPageCPSV;
foot.rows[0].cells[2].innerHTML = iPageCGV;
foot.rows[0].cells[3].innerHTML = iPagePPSV;
foot.rows[0].cells[4].innerHTML = iPagePGV;
foot.rows[1].cells[1].innerHTML = iPageCPSV;
foot.rows[1].cells[2].innerHTML = iPageCGV;
foot.rows[1].cells[3].innerHTML = iPagePPSV;
foot.rows[1].cells[4].innerHTML = iPagePGV;
Or with...
var foot = $('tfoot').first();
foot.children().each(function(i, row) {
row.cells[1].innerHTML = iPageCPSV;
row.cells[2].innerHTML = iPageCGV;
row.cells[3].innerHTML = iPagePPSV;
row.cells[4].innerHTML = iPagePGV;
});
A more modern solution...
var rows = nRow.getElementsByTagName('tfoot')[0].rows,
data = [iPageCPSV, iPageCGV, iPagePPSV, iPagePGV];
[].forEach.call(rows, function(el, i) {
data.forEach(function(item, ii) {
el.cells[ii + 1].innerHTML = item;
});
});
Since you need different data for each cell, I'd suggest putting it all in an Array, getting a collection of all the elements, and pairing the two...
var data = [iPageCPSV, iPageCGV, iPagePPSV, iPagePGV, 'foo', 'bar', 'baz', 'buz'];
$('tfoot > tr > th:not(:first-child)').html(function(i, el) {
return data[i];
});

Categories

Resources