How do I bind a table in a form to a HashSet in Spring Boot? - spring

I am not quite sure how to approach this problem. I have a table rendered by datatables populated with product information. I am trying to figure out a form where I can insert the quantity and discount values and then save either the selected fields or fields where the quantity > 0. Then bind the table data to a set or a list.
However, I am not quite sure how to write the bindings. I have read over this question here but it didn't seem quite the same in that I don't think I could use an index as there could a large amount of products and therefore potentially a large amount of nulls in the response. Any help would be appreciated.
Product.java
#Entity
#Table(name="products")
public class Product {
#Getter
#Setter
#Id
private Long productId;
#Getter
#Setter
private Long productName;
}
QuoteForm.java
public class QuoteForm {
#Getter
#Setter
private Long quoteId;
#Getter
#Setter
private Long contactId;
#Getter
#Setter
private Set<ProductEntry> products;
}
ProductEntry.java
public class ProductEntry {
#Getter
#Setter
private TempProduct product;
#Getter
#Setter
private Long quantity;
#Getter
#Setter
private float discount;
}
form.html
<form id="productTable" th:object="${quoteForm}">
<input type="number" th:field="*{contactId}"></input>
<table id ="productList"
class="table table-striped table-bordered"
cellspacing="0"
width="100%">
<thead>
<tr>
<th>Name</th>
<th>Quantity</th>
<th>Discount</th>
</tr>
</thead>
<tbody>
<tr th:each="product : ${productData.getProducts()}">
<td name="?">
<a th:text="${product.getProductName()}"
th:href="#{|/product/records/${product.getProductId()}|}">
</a>
</td>
<td>
<input type="number"
name="?"
th:field="*{products.quantity}">
</input>
</td>
<td>
<input type="number" name="?" th:field="*{products.discount}"></input>
</td>
</tr>
</tbody>

You can do binding using "model.addAttribute()". Something like this in your controller:
#RequestMapping("/example")
public String formParse(Model model) {
//some logic
Set<ProductEntry> productList = //code to get();
model.addAttribute("productList", productList);
//some more logic
return "yourView";
}
Here "productList" is the name which you have assigned to "?".
And as for checking the quantity you can do that in the form itself, with some thing like:
<div th:if="*{products.quantity>0}" th:field="*{products.quantity}"></div>
Here &gt represents "greater than".
Hope this helps!

Related

Display items into Spring MVC table

I have this Endpoint:
#Controller
public class FileImportsController {
private EntityImportRequestsService entityImportRequestsService;
#Autowired
public FileImportsController(EntityImportRequestsService entityImportRequestsService) {
this.entityImportRequestsService = entityImportRequestsService;
}
#GetMapping("/imported_files")
public String viewHomePage(Model model) {
List<EntityImportRequestsTable> listProducts = entityImportRequestsService.findAll();
System.out.println("Size is " + listProducts.size());
model.addAttribute("listProducts", listProducts);
return "index";
}
}
Entity:
#Getter
#Setter
#NoArgsConstructor
#AllArgsConstructor
#Builder(toBuilder = true)
#Entity
#Table(name = "EntityImportRequests")
public class EntityImportRequestsTable implements Serializable {
#Id
#Column(name = "requestId")
private String requestId;
#Column(name = "transactionGroupId")
private Integer transactionGroupId;
#Column(name = "requestXmlSourceFile")
private String requestXmlSourceFile;
#Column(name = "createdOn")
private LocalDateTime createdOn;
}
Web page index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8"/>
<title>Files Manager</title>
</head>
<body>
<div align="center">
<h1>Files List</h1>
<table border="1" cellpadding="10">
<tr th:each="item : ${listProducts}">
<td th:text="${item.requestId}"/>
<td th:text="${item.transactionGroupId}"/>
<td th:text="${item.requestXmlSourceFile}"/>
<td th:text="${item.createdOn}"/>
</tr>
</table>
</div>
</body>
</html>
When I open the page data is not displayed. What is the proper way to display the data rows from listProducts?
When I make a call to the rest controller directly I get this output:
Hibernate: select entityimpo0_.requestId as requesti1_0_, entityimpo0_.createdOn as createdo2_0_, entityimpo0_.requestXmlSourceFile as requestx3_0_, entityimpo0_.transactionGroupId as transact4_0_ from integration.EntityImportRequests entityimpo0_
Size is 69
As you can see the list is not empty. I have 69 items.
Try something like this.
Just make sure that your listProducts is not empty in your controller.
<tr th:each="product: ${listProducts}">
<td th:text="${product.requestId}" />
<td th:text="${product.name}" />
<td th:text="${product.price}" />
</tr>
Or whatever fields your product entity has next to the name, price, etc.

Insert multiple rows to MySQL with JPA

I am a newbie to spring boot. I have two entities: course1 and course2 with each having a field code, for course code. I have been able to generate select form fields due to entries on couse1 database table so that input to course2 will be selected. However, whenever I make a selection on the form and post, all the selected course codes will enter a single field on course2 database table instead of each entering a separate row. Hence, my problem is, I want to insert multiple rows into a database table using JPA. Following is what I did and will be grateful if any body helps
Course1 entity:
`
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
#Entity
#Table(name = "course_one")
public class CourseOne {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "course_one_id")
private Long courseOneId;
#Column(name = "course_code")
private String code;
#OneToOne(mappedBy = "courseOne")
private CourseTwo courseTwo;
`
Course1 entity contains more fields describing each course though.
Course2 entity:
`
#NoArgsConstructor
#AllArgsConstructor
#Setter
#Getter
#Entity
#Table(name="course_two")
public class CourseTwo{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "course_two_id")
private Long courseTwoId;
private String code;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "course_one_id")
private CourseOne courseOne;
`
Course2 repository
`
public interface CourseTwoRepository extends CrudRepository<CourseTwo, Long> {
}
`
At the service layer, the method I used to insert into the database table for course2 entity is:
`
public List<CourseTwo> saveCourseTwo(CourseTwo courseTwo) {
return(List<CourseTwo>) courseTwoRepo.saveAll(List.of(courseTwo));
}
`
This is my form:
<form action="#" th:action="#{/saveCourseTwo}" th:object="${courseTwo}" method="post">
<div class="overflow-scroll" style="border: 2px; height:dashed; height:300px; width:800px">
<div class="table-responsive">
<table class="table table-sm table-striped table-hover" style="width: 100%">
<thead class="green white-text">
<tr>
<th>Select</th>
<th>Code</th>
<th>Title</th>
<th>Units</th>
</tr>
</thead>
<tbody>
<tr th:each="select : ${listCourseOne}">
<td><input type="hidden" th:value="${select.courseOneId}" name="courseOne"/></td>
<td><input type="checkbox" class="form-check-input" name="code" th:value="${select.code}" />
<td th:text="${select.code}"></td>
<td th:text="${select.title}"></td>
<td th:text="${select.units}"></td>
</tr>
</tbody>
</table>
</div>
</div>
<button type="submit" class="btn btn-success">Save</button>
</form>
However, the method inserts all the selected course codes into a single field. I will be happy if anyone helps.
I also tried to create wrapper multiple instances of CourseTwo as follows:
List<CourseTwo> lisOfCourse =new ArrayList<>(courseTwo);
List<CourseTwo> courseTwoList = new ArrayList<>();
for(int i=0; i<lisOfCourse.size(); i++){
CourseTwo courseTwo1 = new CourseTwo();
courseTwo1.setCourseTwoId(courseTwo1.courseTwoId());
courseTwo1.setCode(courseTwo1.getCode());
courseTwoList.add(courseTwo1);
}
return (List<CourseTwo>) courseTwoRepo.saveAll(courseTwoList);
However, I get the following error: No primary or single unique constructor found for interface java.util.List

Getting all the time: Invalid property of bean class: Bean property is not readable

I always get this error, nonetheless whether I create the getter/setter manually or doing it via Lombok.
So, I guess the error has nothing to do with the Getters/Setters but I cannot find the answer to my problem.
This is my error message:
Invalid property 'person' of bean class [java.util.ArrayList]: Bean property 'person' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
This is my Enttiy class:
#Data
#Getter
#Setter
#Entity
#Table(name="incomeoutgo", schema = "public")
public class IncomeOutgo extends AbstractPersistable<Long> {
#Version
#NotNull
#Column(name ="id")
private Long id;
#Column(name="dayofweek")
private Date dayofweek;
#Column(name="location")
private String location;
#Size(min = 5, max = 50)
#Column(name ="person")
private String person;
#Min(0)
#Column(name ="version")
private Integer version;
#Column(name="income")
private int income;
#Column(name="outgo")
private int outgo;
}
And this is my Controller class
#RequiredArgsConstructor
#Controller
#RequestMapping(value = "/incomeoutgo")
public class IncomeOutgoController {
private static final String INCOMEOUTGO_VIEW = "incomeoutgo";
private final IncomOutgoService incomeoutgoService;
#GetMapping
public String showShop(Model model) {
List<IncomeOutgo> incomeOutgoList = incomeoutgoService.getIncomeOutgoList();
model.addAttribute(INCOMEOUTGO_VIEW, incomeOutgoList);
return INCOMEOUTGO_VIEW;
}
#PostMapping("/incomeoutgo")
public String addUser(#ModelAttribute("incomeoutgo") IncomeOutgo incomeoutgo, BindingResult bindingResult) {
incomeoutgoService.addIncomeOutgo(incomeoutgo);
return "incomeoutgo";
}
}
And last but not least my Thymeleaf template:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Incomes / Expenses</title>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
<table>
<tr>
<th>Id</th>
<th>Day of Week</th>
<th>Name</th>
<th>Location</th>
<th>Income</th>
<th>Expense</th>
</tr>
<tr th:each="incomeoutgo : ${incomeoutgo}">
<td th:text="${incomeoutgo.id}">id</td>
<td th:text="${incomeoutgo.dayofweek}">dayofweek</td>
<td th:text="${incomeoutgo.person}">person</td>
<td th:text="${incomeoutgo.location}">location</td>
<td th:text="${#numbers.formatCurrency(incomeoutgo.income)}">"${#numbers.formatCurrency(incomeoutgo.income)}"</td>
<td th:text="${#numbers.formatCurrency(incomeoutgo.outgo)}">"${#numbers.formatCurrency(incomeoutgo.outgo)}"</td>
</tr>
</table>
<form action="#" th:action="#{/incomeoutgo}" th:object="${incomeoutgo}" method="post">
<table>
<tr>
<td>Name:</td>
<td><input type="text" th:field="*{person}" /></td>
<td th:if="${#fields.hasErrors('person')}" th:errors="*{person}">Name Error</td>
</tr>
<tr>
<td><button type="submit">Submit</button></td>
</tr>
</table>
</form>
</body>
</html>
The error is explained: Invalid property 'person' of bean class [java.util.ArrayList]. You're trying to call getPerson() on a java.util.ArrayList (which doesn't have that property). I suspect it's in your form:
<form ... th:object="${incomeoutgo}">
You've added incomeoutgo to your model as a List<IncomeOutgo>, but you're trying to treat it as an IncomeOutgo instead. You need to create a single object and use that instead when trying to bind form field values.
model.addAttribute(INCOMEOUTGO_VIEW, incomeOutgoList);
model.addAttribute("page", new IncomeOutgo());
.
.
.
<form ... th:object="${page}">
<input type="text" th:field="*{person}" />
(Side node, reusing the same variable name multiple times makes the code confusing. You have the model attribute ${incomeoutgo}, the temporary loop variable th:each="incomeoutgo : ${incomeoutgo}" and the bound thymeleaf object th:object="${incomeoutgo}" which may or may not be related.)

Can't pass an object from one Thymeleaf view to another Thymeleaf view

I'm new to Spring, and I'm working on a Spring MVC + Thymeleaf application that tracks personal expenses. I have a page that shows the list of expenses, and upon clicking "Update" on any given expense, it would show a pre-populated form, on another page, with that expense's information. The problem I'm having is that I want to pass that expense object forward to this second page, but since the data was already fetched from the database in my first page, I wouldn't want to fetch it again from my Spring Data JPA repository.
I think the unusual part of my objective is that I'm trying to pass the object like this:
Controller -> Thymeleaf -> Controller -> Thymeleaf
While the controller has sent an Expenses object to the list of expenses page, I'm trying to resend that same object (or just the one Expense, even better) back to the controller, so it would populate the model in my second form page.
My Expense entity:
package com.williampoletto.expensetracker.entity;
import java.time.LocalDate;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#NoArgsConstructor
#AllArgsConstructor
#Getter
#Setter
#EqualsAndHashCode(of= "id")
#ToString(exclude="categories")
#Entity
#Table
public class Expense {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
private int id;
#NotBlank
private String description;
#NotNull
private double value;
#NotNull
private LocalDate date;
private String note;
#ManyToOne
private User user;
#ManyToMany(cascade=CascadeType.PERSIST)
#JoinTable(
name="expense_category",
joinColumns=#JoinColumn(name="expense_id"),
inverseJoinColumns=#JoinColumn(name="category_id"))
private Set<Category> categories;
public void addCategory(Category category) {
categories.add(category);
}
public void removeCategory(Category category) {
categories.remove(category);
}
public Expense(int id, #NotBlank String description, #NotNull double value, #NotNull LocalDate date,
String note, Set<Category> categories) {
super();
this.id = id;
this.description = description;
this.value = value;
this.date = date;
this.note = note;
this.categories = categories;
}
}
My thymeleaf table:
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th>Description</th>
<th>Value</th>
<th>Category</th>
<th>Note</th>
<th>Date</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr th:each="expense : ${expenses}">
<td th:text="${expense.description}"/>
<td th:text="${expense.value}"/>
<td>
<div th:each="category : ${expense.categories}">
<p th:text ="${category.name}"></p>
</div>
</td>
<td th:text="${expense.note}"/>
<td th:text="${expense.date}"/>
<td>
<form th:action="#{/expenses/showUpdateForm}" th:object="${expense}" method="POST">
<input type="text" name="expense" th:value="${expense.id}">
<input type="text" name="expenseDescription" th:value="${expense.description}">
<input type="text" name="expenseValue" th:value="${expense.value}">
<input type="text" name="expenseDate" th:value="${expense.date}">
<input type="text" name="expenseNote" th:value="${expense.note}">
<input type="text" name="expenseCategories" th:value="${expense.categories}">
<button th:if="${expense.user != null}" type="submit" class="btn btn-info btn-sm">Update</button>
</form>
<a th:href="#{/expenses/delete(expenseId=${expense.id})}"
class="btn btn-danger btn-sm"
onclick="if (!(confirm('Are you sure you want to delete this expense?'))) return false">Delete</a>
</td>
</tbody>
</table>
My /list and /showUpdateForm code for the controller:
#GetMapping("/list")
public String list(#AuthenticationPrincipal UserDetailsImpl userDetails, Model model) {
Set<Expense> expenses = expenseService.findAll(userDetails.getUserId());
model.addAttribute("expenses", expenses);
return "expenses";
}
#PostMapping("/showUpdateForm")
public String showFormForUpdate(#RequestParam("expenseId") int expenseId,
#RequestParam("expenseDescription") String expenseDescription,
#RequestParam("expenseValue") double expenseValue,
#RequestParam("expenseDate") String expenseDate,
#RequestParam("expenseNote") String expenseNote,
#RequestParam("expenseCategories") Set<Category> expenseCategories,
Model model) {
Expense expense = new Expense
(expenseId, expenseDescription, expenseValue, expenseDate, expenseNote, expenseCategories);
model.addAttribute("expense", expense);
return "/expense-form";
}
My final form page:
<form th:action="#{/expenses/save}" th:object="${expense}" method="POST">
<input type="hidden" th:field="*{id}">
<label>Description</label>
<input type="text" th:field="*{description}" class="form-control mb-4 col-4" placeholder="Description">
<label>Value</label>
<input type="text" th:field="*{value}" class="form-control mb-4 col-4" placeholder="Value">
<label>Date</label>
<input type="text" th:field="*{date}" class="form-control mb-4 col-4" placeholder="Date">
<label>Note</label>
<input type="text" th:field="*{note}" class="form-control mb-4 col-4" placeholder="Note">
<label>Categories</label>
<input type="hidden"
th:each="category : *{categories}"
th:value="${category.id}"
th:field="*{categories}"
th:text="${category.name}"/>
<button type="submit" class="btn btn-success col-2 mb-2">Save</button>
</form>
What I have tried:
Instead of sending an object, sending individual values as you can see in my thymeleaf table. The problem with this is that my Expense entity has a LocalDate, User (another entity) and Set attributes, so I had trouble converting these to an Expense object on the controller side. Ideally I would want to write something like this to simply pass on the object, but this example sends a toString:
<form th:action="#{/expenses/showUpdateForm}" th:object="${expense}" method="POST">
<input type="text" name="expense" th:value="${expense}">
</form>
Tried to use an argument to /showUpdateForm to hopefully get the expenses object from the model:
#RequestAttribute("expenses") Set<Expense> expenses
Tried to retrieve the object like this in /showUpdateForm, with the same intent as 2:
Set<Expense> expenses = (Set<Expense>) model.getAttribute("expenses");
Tried to use RedirectAttributes in the controller, which I saw can be useful for passing objects between controllers, but maybe not in my case:
#GetMapping("/showUpdateForm")
public String showFormForUpdate(Model model, RedirectAttributes attributes) {
attributes.addAttribute("expenses");
return "/expense-form";
}
Anyway, I have no idea how to achieve this, I would appreciate any light on the subject! I know that I can easily fix this by simply sending an id from view to controller, then I could perform a repository search of the object with that ID, but that would be cumbersome to the database since the data already exists and was fetched in the previous page.

Spring MVC: list of checkboxes not returned to controller on POST

Why doesn't the server see my list of filled checkboxes?
This question seems to be here asked many times, but the details are so different for each requester that it seems a different answer is needed each time. Here is my story.
These are my data-bearing classes. The Offer contains a list of Filter objects in the filter attribute:.
public class Offer implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id = null;
#Column(name="title")
private String title = null;
[snip]
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name = "offer_filter",
joinColumns = { #JoinColumn(name = "offer_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "filter_id", nullable = false, updatable = false) })
private List<Filter> filters;
[snip]
}
public class Filter implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#NotBlank
#Length(max=100)
#Column(name="text")
private String text;
[snip]
#Transient
private boolean owned = false;
[snip]
}
The simple controller sends the offerEdit.jsp page, with a fully-populated Offer object. The object contains a list of Filters. Because of the owned attribute, only one of the three Filters is pre-checked. This simulates my eventual plan, where the list of Filters is the whole universe and what the Offer owns is a subset.
Note the annotations, that the Offer has the filter list going to the web page but doesn't see it coming back.
public class OfferController {
[snip]
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String getEdit(#RequestParam("id") Long id, Model model, HttpSession session) {
Offer offerAttribute = offerService.get(id);
// At this point, offerAttribute.filters has three elements.
// Mockup -- tells web page that only the middle one of the three Filters should be checked.
List<Filter> filters = offer.getFilters();
Filter filter = filters.get(1);
filter.setOwned(true);
model.addAttribute("offerAttribute", offerAttribute);
return "offer/offerEdit";
}
#RequestMapping(value = "/edit", method = RequestMethod.POST)
public String postEdit(#RequestParam("id") Long id, #Valid #ModelAttribute("offerAttribute") Offer offerAttribute, BindingResult result, HttpSession session, Model model) {
// At this point, offerAttribute.filters is null.
if(result.hasErrors()) {
result.reject("offer.invalidFields");
return "offer/offerEdit";
}
offerAttribute.setId(id);
offerService.edit(offerAttribute);
return "redirect:/offer/list";
}
[snip]
}
The web page has this for its checkbox section. I use form:checkbox over form:checkboxes because I want to use a table,
[snip]
<form:form modelAttribute="offerAttribute" method="POST" action="${saveUrl}">
<table>
<tr>
<td></td>
<td><form:hidden path="id" /></td>
</tr>
<tr>
<td><form:label path="title">Title:</form:label></td>
<td><form:input path="title" size="80" /></td>
<td><form:errors path="title" cssClass="error" /></td>
</tr>
[snip]
</table>
<table>
</table>
<table>
<c:forEach items="${offerAttribute.filters}" var="filter">
<tr>
<td><form:checkbox
path="filters"
label="${filter.text}"
value="${filter.id}"
checked="${filter.owned ? 'true' : ''}" />
</td>
</tr>
</c:forEach>
</table>
[snip]
The displayed web page has three filter checkboxes displayed, with just the middle checkbox filled in.
For the returned list, I expect the server to get only the middle checkbox, which is just what I want.
Here is what the generated checkboxes look like as source:
<table style="border: 1px solid; width: 100%; text-align:left;">
<tr>
<td>
<input id="filters1" name="filters" type="checkbox" value="1"/>
<label for="filters1">Adults (18+) desired, please</label>
<input type="hidden" name="_filters" value="on"/>
</td>
</tr>
<tr>
<td>
<input id="filters2" name="filters" checked="true" type="checkbox" value="2"/>
<label for="filters2">Quiet audiences, please</label>
<input type="hidden" name="_filters" value="on"/>
</td>
</tr>
<tr>
<td>
<input id="filters3" name="filters" type="checkbox" value="4"/>
<label for="filters3">Filter Text First</label>
<input type="hidden" name="_filters" value="on"/>
</td>
</tr>
</table>
My checkbox is set, and in the HTML. To restate my question,
Why doesn't the checkbox value get seen in the controller's POST handler?
Thanks for any answers,
Jerome.
The values of checkboxes could not be directly bind to List.
To get this working you need to create a simple pojo databean that will hold the values of your form fields in jsp. And in that databean to bind the values you need to declare int[] filterId and the values of your checkboxes will bind in that array.
Hope this helps you.
After a lot of web research and different debugging sessions, I came up with a configuration I can live with.
In my controller I provide a model attribute of "filterList", containing List. The "offerAttribute" is an Offer object, containing List filters.
The view has this sequence:
<table>
<c:forEach items="${filterList}" var="filter" varStatus="status">
<tr>
<td><input type="checkbox" name="filters[${status.index}].id"
value="${filter.id}"
${filter.owned ? 'checked' : ''} /> ${filter.text}
</td>
</tr>
</c:forEach>
</table>
When the POST is done the ownerAttribute.filters list is just as long as the original filterList object that created the checkboxes. The checked ones contains a Filter.id value. The unchecked ones contain a null. (That is, the returned filters list is "sparse".) If the user clicks on just a few checkboxes then I must parse the returned list to find those that were chosen.
Once I know the ID values of the checked-on filters, I fetch each of them through Hibernate, put them into my reconstructed Offer object and then persist them to the database.
I realize that I'm not (currently) using the form:checkbox. But it works, and I'm pressed for time here. I'll come back later, perhaps, and see what form:checkbox can do for me.

Resources