Kendo UI Simple Grid - java

I am struggling with using the JSP wrapper in Kendo UI.
I checked their forum and found nothing. I checked stackoverflow and found nothing. I read through the APIs but could not find an answer to my issue.
The call to
url: "CustomerAjaxServlet?str=The R",
returns the following json object:
[
{"id":0,"customerId":"RO113","name":"The Robe Gallery Inc."},
{"id":1,"customerId":"TH204","name":"The Robe Collection"}
]
The grid is being rendered with the correct column headers and the paging is coming back
1 of 10 121 Items. But there is no data.
121 is the character count of the json object.
If I change the call the ajax servlet, the number of items changes too along with the 1 of ...
<%# page language="java" %>
<%# taglib uri="/WEB-INF/tlds/esc.tld" prefix="esc" %>
<%# taglib uri="/WEB-INF/tlds/struts-html.tld" prefix="html" %>
<%# taglib uri="/WEB-INF/tlds/struts-bean.tld" prefix="bean" %>
<%# taglib uri="/WEB-INF/tlds/struts-logic.tld" prefix="logic" %>
<%#taglib prefix="kendo" uri="http://www.kendoui.com/jsp/tags"%>
<%# page import="org.apache.struts.taglib.TagUtils" %>
<% SessionContext context = SessionContext.getSessionContext(request); %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Detail template</title>
<meta http-equiv="Content-Type" content='text/html; charset=us-ascii'>
<meta name='author' content=Test'>
<link href="common/js/kendo/examples/content/shared/styles/examples-offline.css" rel="stylesheet">
<link href="common/js/kendo/styles/kendo.common.min.css" rel="stylesheet">
<link href="common/js/kendo/styles/kendo.default.min.css" rel="stylesheet">
<script src="common/js/kendo/js/jquery.min.js"></script>
<script src="common/js/kendo/js/kendo.web.min.js"></script>
<script src="common/js/kendo/content/shared/js/console.js"></script>
</head>
<body>
<a class="offline-button" href="../index.html">Back</a>
<div id="example" class="k-content">
<div id="grid"></div>
<script type="text/x-kendo-template" id="template">
<div class="tabstrip">
<div>
<div class='customer-details'>
<ul>
<li><label>id:</label>#= id #</li>
<li><label>name:</label>#= name #</li>
<li><label>customerId:</label>#= customerId #</li>
</ul>
</div>
</div>
</div>
</script>
<script>
$(document).ready(function() {
var element = $("#grid").kendoGrid({
dataSource: {
transport: {
read: function(options) {
$.ajax( {
url: "CustomerAjaxServlet?str=The R",
data: options.data, success: function(result) {
options.success(result);
//alert(result);
}
});
}
},
pageSize: 10,
serverPaging: true,
serverSorting: true
},
height: 450,
sortable: true,
pageable: true,
dataBound: function() {
this.expandRow(this.tbody.find("tr.k-master-row").first());
},
columns: [
{
field: "id",
title: "Id"
},
{
field: "name",
title: "Name"
},
{
field: "customerId",
title: "Customer Id"
}
]
});
});
</script>
<style scoped="scoped">
.customer-details ul
{
list-style:none;
font-style:italic;
margin-bottom: 20px;
}
.customer-details label
{
display:inline-block;
width:90px;
font-style:normal;
font-weight:bold;
}
</style>
</div>
</body>
</html>

Your code runs fine. Did you check the contentType of the json object returned? It should be "application/json".
I run your code with the following CustomerAjaxServlet
<%# page contentType="application/json;charset=UTF-8" language="java" %>
<%
out.println("[" +
"{\"id\":0,\"customerId\":\"RO113\",\"name\":\"The Robe Gallery Inc.\"}," +
"{\"id\":1,\"customerId\":\"TH204\",\"name\":\"The Robe Collection\"}" +
"]");
%>

Related

how can i paint a graphic in spring mvc in jsp using highchart

I want to paint a graphic in jsp unsando spring mvc and highchart, but I still can't do it,
I wait for your answer thank you
my view, This is where I want to paint the graph but the graph is not shown, it shows nothing
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%# taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>Chart</title>
<script src="resources/assets/js/highcharts.js"></script>
<script src="resources/assets/js/highcharts-3d.js"></script>
<!-- <script src="resources/assets/js/jquery.js"></script> -->
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
</head>
<body class="page-container-bg-solid">
<div class="page-container">
<div class="page-content-wrapper">
<div class="page-head" style="background-color:#eff3f8;padding-top:40px">
<div class="container">
<div class="row" style="margin-bottom:30px">
<div class="col-md-6">
<h1>my Chart</h1>
</div>
</div>
<div class="row" style="margin-bottom:30px">
<div class="col-md-6" style="margin-top:20px">
<div id="mychart" style="width:100%; height:400px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
$(function () {
Highcharts.setOptions({
global: {
useUTC: false
}
});
drawSalesByTypeChart();
drawSalesByRegionChart();
});
function drawSalesByRegionChart() {
var salesByRegionChart = Highcharts.chart('mychart', {
chart: {
type: 'pie',
margin: 40,
options3d: {
enabled: true,
alpha: 45,
beta: 0
}
},
title: {
text: 'Sales by Region'
},
plotOptions: {
pie: {
allowPointSelect: true,
depth: 35
}
},
series: [{
name: 'Regions',
colorByPoint:true,
data: [{
name: 'Northeast',
y: [[${listGraph}]]
}
]
}]
});
}
</script>
</body>
</html>
my controller
#RequestMapping(value = "/graphReport")
public String combo(QcReport qc, Model model) throws IOException {
List<QcReport> listGraph = assayServ.listGraphAssay();
model.addAttribute("listGraph", listGraph);
return ("graphReport");
}
When I am comparing your work below tutorial:
https://careydevelopment.us/2017/07/01/add-charts-spring-boot-app-highchart/
You are trying to draw a pie chart which needs integer value while you are passing a list ${listGraph}.
series: [{
name: 'Regions',
colorByPoint:true,
data: [{
name: 'Northeast',
y: [[${listGraph}]]
}
]

Unable to link a column in datatables

<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Populating JSP</title>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="http://cdn.datatables.net/1.10.0/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="http://cdn.datatables.net/1.10.0/css/jquery.dataTables.css" />
<link rel="stylesheet" href="http://cdn.datatables.net/1.10.2/css/jquery.dataTables.css" />
</head>
<body>
<table id="example" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>id</th>
<th>salary</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
$(document).ready(function() {
$('#example').dataTable( {
serverSide: true,
"fnRowCallback": function( nRow, aData, iDisplayIndex ) {
$('td:eq(2)', nRow).html('<a href="http://www.google.com' + aData[2] + '">' +
aData[2] + '</a>');
return nRow;
},
ajax : {
url: 'hello/data1',
dataType:'json',
type: 'POST'
}
}
);
});
</script>
</body>
</html>
I have 2 coulmns, ID and Salary. I am linking the salary to google.com, for that I am using fnRowCallback function. But that doesn't seem to work. Where do you think I am going wrong. The jsp is shown above.
Use custom column definition columnDefs to alter column rendering.
$('#example').dataTable( {
serverSide: true,
"aoColumnDefs" : [
{
"mData": "name",
"sClass": "dataTable-user-list-name",
"fnRender": function (oObj) {
return '<a href="/#/' + oObj.aData['detailsUrl'] + '">oObj.aData['name']<a>'
}],
ajax : {
url: 'hello/data1',
dataType:'json',
type: 'POST'
}
}

populating google PIE chart with java string returned through ajax

I am using this Google Pic Chart for the first time and hence I would request you to help me in resolving the below issue.
I am using two charts: Bar chart and Pie chart. If i click a particular column in the bar chart the corresponding pie chart should be loaded in the same screen, the value for the pie chart is populated using an ajax call. The issue is that I am returning a string in the form of javascript arraylist. I can see that the returned string is in correct format but I am getting Uncaught Error : Not an Array.
I am using google.visualization.arrayToDataTable() method to generate the Pie Chart. Please provide your valuable help to resolve this. Code given below.
JSP Code:
*********
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%# taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%# taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%# taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Incident Entry</title>
<link href="css/style_strauto.css" type="text/css" rel="stylesheet" />
<link href='css/ui-lightness/jquery-ui.min.css' type="text/css"
rel="stylesheet" />
<link href='css/warning_style.css' type="text/css" rel="stylesheet" />
<link href='css/timePicker.css' type="text/css" rel="stylesheet" />
<script type="text/javascript"
src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['corechart']}]}"></script>
<script type="text/javascript"
src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {
packages : [ "corechart" ]
});
var barChart;
var piChart;
google.setOnLoadCallback(drawChart);
var barData = google.visualization
.arrayToDataTable([ <c:out value="${incidentArray}" escapeXml="false" /> ]);
var piData = google.visualization
.arrayToDataTable(<c:out value="${piChatArray}" escapeXml="false" />);
function drawChart() {
var barView = new google.visualization.DataView(barData);
barView.setColumns([ 0, 1, {
calc : "stringify",
sourceColumn : 1,
type : "string",
role : "annotation"
}, 2 ]);
var barOptions = {
title : "Top 10 CI's with High Incidents",
width : 500,
height : 350,
bar : {
groupWidth : "95%"
},
legend : {
position : "none"
},
is3D : true
};
var piOptions = {
width : 500,
height : 350,
title : 'Detail Analysis of CI\'s',
is3D : true
};
var piChart = new google.visualization.PieChart(document
.getElementById('piechart'));
barChart = new google.visualization.ColumnChart(document
.getElementById("columnchart_values"));
piChart.draw(piData, piOptions);
barChart.draw(barView, barOptions);
google.visualization.events.addListener(barChart, 'select',
myClickHandler);
function myClickHandler(e) {
var row = "";
var column = "";
var selection = barChart.getSelection();
for (var i = 0; i < selection.length; i++) {
var item = selection[i];
if (item.row != null && item.column != null) {
row = item.row;
column = item.column;
} else if (item.row != null) {
row = item.row;
} else if (item.column != null) {
column = item.column;
}
}
makeServerAjaxCall(row,column);
//var piArrayList =$('#result').text();
var piArrayList = [["Incidents","Percentage"],["Resolver Self-Creation",38],];
//var res = piArrayList.split("|");
alert(piArrayList);
piData = google.visualization.arrayToDataTable(piArrayList);
drawChart();
}
}
function makeServerAjaxCall(row, column) {
var returnVal;
$.ajax({
type : 'GET', // Or any other HTTP Verb (Method)
url : 'incident_managment_pichart.htm',
data : {
rowVal : row,
colVal : column
},
async : false,
// async * false = !async = sync
success : function(responseText) {
//alert($.parseJSON(responseText));
$("#result").html(responseText);
returnVal = $("#result").html(responseText);
},
error : function(e) {
alert("An error occured: " + e.status + " " + e.statusText);
returnVal = '';
}
});
return returnVal;
}
//Ajax Call for getting PI Chart Data
//
</script>
<style>
table {
font-family: arial, helvetica;
font-size: 10pt;
cursor: default;
margin: 0;
background: rgb(252, 248, 248);
border-spacing: 0;
color: black;
}
</style>
</head>
<body>
<form:form id="barChartForm" method="GET"
action="incident_managment_pichart.htm">
<!-- Header Start -->
<div id="hd">
<div class="inner">
<a class="logo" href="#">Logo</a>
<h1 class="appName">Incident Report</h1>
</div>
</div>
<!-- Header End -->
<!-- Nav Start -->
<div id="nav">
<div class="inner">
<div class="userProfile">
<img src="images/icoProfile.png" alt="User" /> <span><spring:message
code="capone.ito.dashboard.common.header.label.analyser" /></span>
</div>
<div class="links">
<a href="dashBoardHome.htm"> <spring:message
code="capone.ito.dashboard.common.header.label.home" />
</a>
</div>
<div class="menu">
<a href="##"><spring:message
code="capone.ito.dashboard.common.menu.label.dailyBoard" /></a> | <a
href="##"><spring:message
code="capone.ito.dashboard.common.menu.label.weeklyBoard" /></a> | <a
href="##"><spring:message
code="capone.ito.dashboard.common.menu.label.monthlyBoard" /></a> |
<a href="##"><spring:message
code="capone.ito.dashboard.common.menu.label.notification" /></a> |
<a href="##"><spring:message
code="capone.ito.dashboard.common.menu.label.upload" /></a>
</div>
</div>
</div>
<div style="margin-bottom: -20px;" id="bgnone" class="inner bdBGHome">
<div class="clearboth ">
<table>
<tr>
<td><div id="columnchart_values"
style="width: 475px; height: 350px;"></div></td>
<td><div id="piechart" style="width: 475px; height: 350px;"></div>
<div id="result"></div></td>
</table>
</div>
</div>
</form:form>
<!-- Footer Start -->
<div id="ft" class="inner">
<span class="copyrights"></span>
</div>
<!-- Footer End -->
</body>
</html>
Response from AJAX:
******************
[["Incidents","Percentage"],["Resolver Self-Creation",38],]
AJAX Method call
*****************
public String doGeneratePIChart(ModelMap model, #RequestParam String rowVal,#RequestParam String colVal, HttpServletRequest request,
HttpServletResponse response) throws NumberFormatException, Exception
{
logger.debug("[IncidentManagementController doGeneratePIChart] : start");
String piArray;
List<PIChartVO> piChartVOList = new ArrayList<PIChartVO>();
int row = Integer.valueOf(rowVal);
IncidentRequestVO incidentVO = new IncidentRequestVO();// (IncidentRequestVO)
// model.get("incidentRequestVO");
piChartVOList = incidentManageBO.getPIChartVO("ENVITOWINTELPROD");
logger.debug("[IncidentManagementController : doGeneratePIChart] Array length :" + piChartVOList.size());
piArray = toPIJavascriptArray(piChartVOList);
logger.debug("[IncidentManagementController : doGeneratePIChart] Array String using internal -" + piArray);
incidentVO.setPiChartList(piArray);
logger.debug("[IncidentManagementController : doGeneratePIChart] row, column values :" + rowVal + "," + colVal);
try {
response.getWriter().write(piArray);
} catch (IOException e) {
logger.error("Error occure while retriving the server Details value " + e); }
return null;
}
I resolved using the below code and removing the extra "," that was dislayed in Response from AJAX
var piArrayList = makeServerAjaxCall(row,column);
var obj = $.parseJSON(piArrayList);
piData = google.visualization.arrayToDataTable(obj);
drawChart();
Thanks for your help anyway :-)

JSON data is not visible in jqgrid

I am quite new with JSON. I want to show the java object data as JSON data. I have done some code but it is showing only the grid, not the grid data.
My jsp page looks like this:
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%#taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%# page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Jeeni Software - jQuery Ajax Data Grid Example</title>
<c:set var="baseURL" value="${pageContext.request.contextPath}"/>
<script type="text/javascript" src="${baseURL}/js/jquery.min.js"></script>
<script type="text/javascript" src="${baseURL}/js/jquery.jqGrid.min.js"></script>
<script type="text/javascript" src="${baseURL}/js/jquery-ui.min.js"></script>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="css/redmond/jquery-ui.css">
<link rel="stylesheet" href="css/redmond/jquery.ui.theme.css">
<link rel="stylesheet" href="css/jqgrid/ui.jqgrid.css">
<!-- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script> -->
<!-- <script src="http://www.trirand.com/blog/jqgrid/js/i18n/grid.locale-en.js" type="text/javascript"></script> -->
<!-- <script src="http://www.trirand.com/blog/jqgrid/js/jquery.jqGrid.min.js" type="text/javascript"></script> -->
<!-- <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.0/jquery-ui.min.js"></script> -->
<script>
$(document).ready(function() {
setupGrid();
attachSendDataEvent();
attachDeleteButton();
});
function attachSendDataEvent(){
$("#sendData").click(function(){
var data = "firstName=" + $("#firstName").val() + "&" +
"lastName=" + $("#lastName").val() + "&" +
"address=" + $("#address").val() + "&" +
"postcode=" + $("#postcode").val();
$.post("data/person/put",
data,
dataSentOK
);
});
return false;
}
function attachDeleteButton(){
$("#deleteBtn").click(function(){
var grid = jQuery("#dataTable").jqGrid();
var rowNum = grid.getGridParam('selrow');
if(rowNum){
var person = grid.getRowData(rowNum);
var data = "perId=" + person.id;
$.post("data/person/delete",
data,
dataSentOK
);
}
});
}
function dataSentOK(){
jQuery("#dataTable").jqGrid().trigger("reloadGrid");
}
function setupGrid(){
jQuery("#dataTable").jqGrid({
url: "data/person/get",
datatype: "json",
loadonce : false,
jsonReader: {root : "rows", repeatitems: false, id: "id"},
colNames:['ID','First Name','Last Name', 'Address', 'Postcode'],
colModel:[
{name:'id',index:'id', width:20},
{name:'firstName',index:'firstName', width:100},
{name:'lastName',index:'lastName', width:100},
{name:'address',index:'address', width:380},
{name:'postcode',index:'postcode', width:100}
],
rowNum:4,
rowList:[5,10,20,30],
height:200,
pager: "#pagingDiv",
viewrecords: true,
caption: "Names and Addresses"
}).navGrid('#pager', {edit:false,add:false,del:false, search: false});
}
</script>
</head>
<body>
<div class="centreDiv">
<div class="heading"><h1>Jeeni Software - jQuery Ajax Data Grid Example</h1></div>
<div>
<div style="height:170px;">
<div class="form">
<div class="padding">
<label>First Name:</label> <input id="firstName"/><br/>
<label>Last Name:</label> <input id="lastName"/><br/>
<label>Address:</label> <input id="address" size="40"><br/>
<label>Postcode:</label> <input id="postcode"/><br/>
<button id="sendData">Send</button>
</div>
</div>
</div>
<!-- jqGrid will be injected into this DIV-->
<h2>jqGrid Data Table</h2>
<div>
<table id="dataTable"></table>
<div id="pagingDiv"></div>
<button id="deleteBtn">Delete Row</button>
</div>
</div>
</div>
</body>
</html>
And the spring controller like this:
#RequestMapping(value="get", method = RequestMethod.GET)
#ResponseBody
public JqGridData<Person> getPeople(#RequestParam("page") int page,
#RequestParam("rows") int rows,
#RequestParam("sidx") String sortColumnId,
#RequestParam("sord") String sortDirection){
int totalNumberOfPages = GridUtils.getTotalNumberOfPages(people, rows);
int currentPageNumber = GridUtils.getCurrentPageNumber(people, page, rows);
int totalNumberOfRecords = people.size();
List<Person> pageData = GridUtils.getDataForPage(people, page, rows);
JqGridData<Person> gridData = new JqGridData<Person>(totalNumberOfPages, currentPageNumber, totalNumberOfRecords, pageData);
return gridData;
}
Can anybody please tell me what's wrong with this code?

Use JQuery SWF plugin in JSP

I used an example script of how to load an SWF file with the JQuery SWF plugin (http://jquery.thewikies.com/swfobject/examples). I am trying to get the plugin to work in a JSP. It appears to work in FireFox and Chrome but not in IE8.
Can anyone see any obvious issues? Thanks in advance.
<%# taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="js/jquery-1.4.2.js"></script>
</head>
<script type="text/javascript" src="js/jquery.swfobject.1-1-1.js"></script>
<body>
<script type="text/javascript">
var bar_chart = $.flash.create (
{
swf: 'flash/open-flash-chart.swf',
width: 350,
height: 260,
wmode: 'transparent',
play: true,
flashvars: {
"get-data": "getChart1Data"
}
}
);
function getChart1Data()
{
return JSON.stringify(${chart1Data});
};
function ofc_ready()
{
/**/
};
$(document).ready(
function() {
$('#bar_chart').html(bar_chart);
}
);
</script>
<tr>
<td colspan="2">
<table>
<tr>
<td>
<div id="bar_chart"></div>
</td>
</tr>
</table>
</td>
</tr>
</body>
</html>
Your HTML is syntactically invalid. The browser behaviour is unpredictable.
This one is syntactically valid. Give it a try.
<%# taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>Insert your title</title>
<script type="text/javascript" src="js/jquery-1.4.2.js"></script>
<script type="text/javascript" src="js/jquery.swfobject.1-1-1.js"></script>
<script type="text/javascript">
var bar_chart = $.flash.create ({
swf: 'flash/open-flash-chart.swf',
width: 350,
height: 260,
wmode: 'transparent',
play: true,
flashvars: {
"get-data": "getChart1Data"
}
});
function getChart1Data() {
return JSON.stringify(${chart1Data});
}
function ofc_ready() {
/**/
}
$(document).ready(function() {
$('#bar_chart').html(bar_chart);
});
</script>
</head>
<body>
<div id="bar_chart"></div>
</body>
</html>
PS: I removed the table since it's incomplete and only adds noise to the demo.
All you have to do is change your swfobject version to latest SWFObject 2.2
<script type="text/javascript" src="js/jquery.swfobject.1-1-1.js"></script>
This will fix ie issue
try
flashMovie = null;
$(document).ready(
function () {
flashMovie = $('#bar_chart');
flashMovie.flash(
{
swf: 'flash/open-flash-chart.swf',
width: 350,
height: 260,
wmode: 'transparent',
play: true,
flashvars: { "get-data": "getChart1Data" }
}
);
}
);
function getChart1Data() { return JSON.stringify(${chart1Data}); };

Categories

Resources