[BAEL-1686] - Update project after editor's article review
This commit is contained in:
parent
f8b9555e42
commit
2b08d2c7ce
|
@ -1,10 +1,8 @@
|
||||||
package com.baeldung;
|
package com.baeldung;
|
||||||
|
|
||||||
import com.baeldung.controller.repository.AddressAvailabilityRepository;
|
|
||||||
import com.baeldung.controller.repository.AddressRepository;
|
import com.baeldung.controller.repository.AddressRepository;
|
||||||
import com.baeldung.controller.repository.UserRepository;
|
import com.baeldung.controller.repository.UserRepository;
|
||||||
import com.baeldung.entity.Address;
|
import com.baeldung.entity.Address;
|
||||||
import com.baeldung.entity.AddressAvailability;
|
|
||||||
import com.baeldung.entity.User;
|
import com.baeldung.entity.User;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
|
@ -15,31 +13,32 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
@SpringBootApplication @EntityScan("com.baeldung.entity") @EnableJpaRepositories("com.baeldung.controller.repository")
|
@SpringBootApplication
|
||||||
@EnableAutoConfiguration public class Application {
|
@EntityScan("com.baeldung.entity")
|
||||||
|
@EnableJpaRepositories("com.baeldung.controller.repository")
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
public class Application {
|
||||||
|
|
||||||
@Autowired private UserRepository personRepository;
|
@Autowired
|
||||||
@Autowired private AddressRepository addressRepository;
|
private UserRepository personRepository;
|
||||||
@Autowired private AddressAvailabilityRepository addressAvailabilityRepository;
|
@Autowired
|
||||||
|
private AddressRepository addressRepository;
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
SpringApplication.run(Application.class, args);
|
SpringApplication.run(Application.class, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct private void initializeData() {
|
@PostConstruct
|
||||||
|
private void initializeData() {
|
||||||
// Create John
|
// Create John
|
||||||
final AddressAvailability addressOneAvailability = new AddressAvailability(true, true, false, false, false, true, true);
|
|
||||||
addressAvailabilityRepository.save(addressOneAvailability);
|
|
||||||
final User john = new User("John");
|
final User john = new User("John");
|
||||||
personRepository.save(john);
|
personRepository.save(john);
|
||||||
final Address addressOne = new Address("Fake Street 1", "Fake Country", addressOneAvailability, john);
|
final Address addressOne = new Address("Fake Street 1", "Spain", john);
|
||||||
addressRepository.save(addressOne);
|
addressRepository.save(addressOne);
|
||||||
// Create Lisa
|
// Create Lisa
|
||||||
final AddressAvailability addressTwoAvailability = new AddressAvailability(false, false, false, false, false, true, true);
|
|
||||||
addressAvailabilityRepository.save(addressTwoAvailability);
|
|
||||||
final User lisa = new User("Lisa");
|
final User lisa = new User("Lisa");
|
||||||
personRepository.save(lisa);
|
personRepository.save(lisa);
|
||||||
final Address addressTwo = new Address("Real Street 1", "Real Country", addressTwoAvailability, lisa);
|
final Address addressTwo = new Address("Real Street 1", "Germany", lisa);
|
||||||
addressRepository.save(addressTwo);
|
addressRepository.save(addressTwo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package com.baeldung.controller;
|
package com.baeldung.controller;
|
||||||
|
|
||||||
import com.baeldung.controller.repository.AddressAvailabilityRepository;
|
|
||||||
import com.baeldung.controller.repository.AddressRepository;
|
import com.baeldung.controller.repository.AddressRepository;
|
||||||
import com.baeldung.controller.repository.UserRepository;
|
import com.baeldung.controller.repository.UserRepository;
|
||||||
import com.baeldung.entity.Address;
|
import com.baeldung.entity.Address;
|
||||||
import com.baeldung.entity.AddressAvailability;
|
|
||||||
import com.baeldung.entity.User;
|
import com.baeldung.entity.User;
|
||||||
import com.querydsl.core.BooleanBuilder;
|
import com.querydsl.core.BooleanBuilder;
|
||||||
import com.querydsl.core.types.Predicate;
|
import com.querydsl.core.types.Predicate;
|
||||||
|
@ -14,11 +12,13 @@ import org.springframework.http.MediaType;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController public class QueryController {
|
@RestController
|
||||||
|
public class QueryController {
|
||||||
|
|
||||||
@Autowired private UserRepository personRepository;
|
@Autowired
|
||||||
@Autowired private AddressRepository addressRepository;
|
private UserRepository personRepository;
|
||||||
@Autowired private AddressAvailabilityRepository addressAvailabilityRepository;
|
@Autowired
|
||||||
|
private AddressRepository addressRepository;
|
||||||
|
|
||||||
@GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/users", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public Iterable<User> queryOverUser(@QuerydslPredicate(root = User.class) Predicate predicate) {
|
public Iterable<User> queryOverUser(@QuerydslPredicate(root = User.class) Predicate predicate) {
|
||||||
|
@ -31,11 +31,4 @@ import org.springframework.web.bind.annotation.RestController;
|
||||||
final BooleanBuilder builder = new BooleanBuilder();
|
final BooleanBuilder builder = new BooleanBuilder();
|
||||||
return addressRepository.findAll(builder.and(predicate));
|
return addressRepository.findAll(builder.and(predicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/addressAvailabilities", produces = MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
public Iterable<AddressAvailability> queryOverAddressAvailability(
|
|
||||||
@QuerydslPredicate(root = AddressAvailability.class) Predicate predicate) {
|
|
||||||
final BooleanBuilder builder = new BooleanBuilder();
|
|
||||||
return addressAvailabilityRepository.findAll(builder.and(predicate));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
package com.baeldung.controller.repository;
|
|
||||||
|
|
||||||
import com.baeldung.entity.AddressAvailability;
|
|
||||||
import com.baeldung.entity.QAddressAvailability;
|
|
||||||
import com.querydsl.core.types.dsl.StringExpression;
|
|
||||||
import com.querydsl.core.types.dsl.StringPath;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
|
|
||||||
import org.springframework.data.querydsl.binding.QuerydslBinderCustomizer;
|
|
||||||
import org.springframework.data.querydsl.binding.QuerydslBindings;
|
|
||||||
import org.springframework.data.querydsl.binding.SingleValueBinding;
|
|
||||||
|
|
||||||
public interface AddressAvailabilityRepository
|
|
||||||
extends JpaRepository<AddressAvailability, Long>, QueryDslPredicateExecutor<AddressAvailability>,
|
|
||||||
QuerydslBinderCustomizer<QAddressAvailability> {
|
|
||||||
@Override default void customize(final QuerydslBindings bindings, final QAddressAvailability root) {
|
|
||||||
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::eq);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,8 @@ import org.springframework.data.querydsl.binding.SingleValueBinding;
|
||||||
|
|
||||||
public interface AddressRepository
|
public interface AddressRepository
|
||||||
extends JpaRepository<Address, Long>, QueryDslPredicateExecutor<Address>, QuerydslBinderCustomizer<QAddress> {
|
extends JpaRepository<Address, Long>, QueryDslPredicateExecutor<Address>, QuerydslBinderCustomizer<QAddress> {
|
||||||
@Override default void customize(final QuerydslBindings bindings, final QAddress root) {
|
@Override
|
||||||
|
default void customize(final QuerydslBindings bindings, final QAddress root) {
|
||||||
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::eq);
|
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::eq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,8 @@ import org.springframework.data.querydsl.binding.SingleValueBinding;
|
||||||
|
|
||||||
public interface UserRepository
|
public interface UserRepository
|
||||||
extends JpaRepository<User, Long>, QueryDslPredicateExecutor<User>, QuerydslBinderCustomizer<QUser> {
|
extends JpaRepository<User, Long>, QueryDslPredicateExecutor<User>, QuerydslBinderCustomizer<QUser> {
|
||||||
@Override default void customize(final QuerydslBindings bindings, final QUser root) {
|
@Override
|
||||||
|
default void customize(final QuerydslBindings bindings, final QUser root) {
|
||||||
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::eq);
|
bindings.bind(String.class).first((SingleValueBinding<StringPath, String>) StringExpression::eq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +1,33 @@
|
||||||
package com.baeldung.entity;
|
package com.baeldung.entity;
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
|
|
||||||
@Entity @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class Address {
|
@Entity
|
||||||
|
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
|
||||||
|
public class Address {
|
||||||
|
|
||||||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false) private Long id;
|
@Id
|
||||||
@Column private String address;
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@Column private String country;
|
@Column(name = "id", unique = true, nullable = false)
|
||||||
@OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "address_id") @JsonBackReference private AddressAvailability
|
private Long id;
|
||||||
addressAvailability;
|
@Column
|
||||||
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id") @JsonBackReference private User user;
|
private String address;
|
||||||
|
@Column
|
||||||
|
private String country;
|
||||||
|
@OneToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "user_id")
|
||||||
|
private User user;
|
||||||
|
|
||||||
public Address() {
|
public Address() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Address(String address, String country, AddressAvailability addressAvailability, User user) {
|
public Address(String address, String country, User user) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.country = country;
|
this.country = country;
|
||||||
this.addressAvailability = addressAvailability;
|
|
||||||
this.user = user;
|
this.user = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,12 +54,4 @@ import javax.persistence.*;
|
||||||
public void setCountry(String country) {
|
public void setCountry(String country) {
|
||||||
this.country = country;
|
this.country = country;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AddressAvailability getAddressAvailability() {
|
|
||||||
return addressAvailability;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddressAvailability(AddressAvailability addressAvailability) {
|
|
||||||
this.addressAvailability = addressAvailability;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,114 +0,0 @@
|
||||||
package com.baeldung.entity;
|
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
|
||||||
|
|
||||||
import javax.persistence.*;
|
|
||||||
|
|
||||||
@Table(name = "address_availability") @Entity @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
|
|
||||||
public class AddressAvailability {
|
|
||||||
|
|
||||||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false) private Long id;
|
|
||||||
@Column private Boolean monday;
|
|
||||||
@Column private Boolean tuesday;
|
|
||||||
@Column private Boolean wednesday;
|
|
||||||
@Column private Boolean thursday;
|
|
||||||
@Column private Boolean friday;
|
|
||||||
@Column private Boolean saturday;
|
|
||||||
@Column private Boolean sunday;
|
|
||||||
@OneToOne(mappedBy = "addressAvailability") @JsonManagedReference private Address address;
|
|
||||||
|
|
||||||
public AddressAvailability() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public AddressAvailability(Boolean monday, Boolean tuesday, Boolean wednesday, Boolean thursday, Boolean friday,
|
|
||||||
Boolean saturday, Boolean sunday) {
|
|
||||||
this.monday = monday;
|
|
||||||
this.tuesday = tuesday;
|
|
||||||
this.wednesday = wednesday;
|
|
||||||
this.thursday = thursday;
|
|
||||||
this.friday = friday;
|
|
||||||
this.saturday = saturday;
|
|
||||||
this.sunday = sunday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getMonday() {
|
|
||||||
return monday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMonday(Boolean monday) {
|
|
||||||
this.monday = monday;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getTuesday() {
|
|
||||||
return tuesday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setTuesday(Boolean tuesday) {
|
|
||||||
this.tuesday = tuesday;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getWednesday() {
|
|
||||||
return wednesday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setWednesday(Boolean wednesday) {
|
|
||||||
this.wednesday = wednesday;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getThursday() {
|
|
||||||
return thursday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setThursday(Boolean thursday) {
|
|
||||||
this.thursday = thursday;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getFriday() {
|
|
||||||
return friday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFriday(Boolean friday) {
|
|
||||||
this.friday = friday;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getSaturday() {
|
|
||||||
return saturday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSaturday(Boolean saturday) {
|
|
||||||
this.saturday = saturday;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Boolean getSunday() {
|
|
||||||
return sunday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSunday(Boolean sunday) {
|
|
||||||
this.sunday = sunday;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Address getAddress() {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAddress(Address address) {
|
|
||||||
this.address = address;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,17 +1,22 @@
|
||||||
package com.baeldung.entity;
|
package com.baeldung.entity;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
|
|
||||||
@Entity @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) public class User {
|
@Entity
|
||||||
|
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
|
||||||
|
public class User {
|
||||||
|
|
||||||
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id", unique = true, nullable = false) private Long id;
|
@Id
|
||||||
@Column private String name;
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
@OneToMany(fetch = FetchType.LAZY, mappedBy = "user") @JsonManagedReference private List<Address> addresses;
|
@Column(name = "id", unique = true, nullable = false)
|
||||||
|
private Long id;
|
||||||
|
@Column
|
||||||
|
private String name;
|
||||||
|
@OneToOne(fetch = FetchType.LAZY, mappedBy = "user")
|
||||||
|
private Address address;
|
||||||
|
|
||||||
public User() {
|
public User() {
|
||||||
}
|
}
|
||||||
|
@ -36,11 +41,11 @@ import java.util.List;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Address> getAddresses() {
|
public Address getAddress() {
|
||||||
return addresses;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAddresses(List<Address> addresses) {
|
public void setAddress(Address address) {
|
||||||
this.addresses = addresses;
|
this.address = address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,33 +20,46 @@ import static org.hamcrest.Matchers.is;
|
||||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = Application.class) @WebAppConfiguration
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@SpringBootTest(classes = Application.class)
|
||||||
|
@WebAppConfiguration
|
||||||
public class QuerydslIntegrationTest {
|
public class QuerydslIntegrationTest {
|
||||||
|
|
||||||
final MediaType contentType =
|
final MediaType contentType =
|
||||||
new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
|
new MediaType(MediaType.APPLICATION_JSON.getType(), MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));
|
||||||
|
|
||||||
@Autowired private WebApplicationContext webApplicationContext;
|
@Autowired
|
||||||
|
private WebApplicationContext webApplicationContext;
|
||||||
|
|
||||||
private MockMvc mockMvc;
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
@Before public void setupMockMvc() {
|
@Before
|
||||||
|
public void setupMockMvc() {
|
||||||
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
|
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void givenRequestHasBeenMade_whenQueryAddressFilteringByUserName_thenGetJohn() throws Exception {
|
@Test
|
||||||
mockMvc.perform(get("/addresses?user.name=John")).andExpect(status().isOk()).andExpect(content().contentType(contentType))
|
public void givenRequest_whenQueryUserFilteringByCountrySpain_thenGetJohn() throws Exception {
|
||||||
.andExpect(jsonPath("$", hasSize(1))).andExpect(jsonPath("$[0].address", is("Fake Street 1")))
|
mockMvc.perform(get("/users?address.country=Spain")).andExpect(status().isOk()).andExpect(content()
|
||||||
.andExpect(jsonPath("$[0].country", is("Fake Country")));
|
.contentType
|
||||||
|
(contentType))
|
||||||
|
.andExpect(jsonPath("$", hasSize(1)))
|
||||||
|
.andExpect(jsonPath("$[0].name", is("John")))
|
||||||
|
.andExpect(jsonPath("$[0].address.address", is("Fake Street 1")))
|
||||||
|
.andExpect(jsonPath("$[0].address.country", is("Spain")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test public void givenRequestHasBeenMade_whenQueryOverAddressAvailabilityFilteringByAddressCountry_thenGetAvailability()
|
@Test
|
||||||
throws Exception {
|
public void givenRequest_whenQueryUserWithoutFilter_thenGetJohnAndLisa() throws Exception {
|
||||||
mockMvc.perform(get("/addressAvailabilities?address.country=Real Country")).andExpect(status().isOk())
|
mockMvc.perform(get("/users")).andExpect(status().isOk()).andExpect(content()
|
||||||
.andExpect(content().contentType(contentType)).andExpect(jsonPath("$", hasSize(1)))
|
.contentType
|
||||||
.andExpect(jsonPath("$[0].monday", is(false))).andExpect(jsonPath("$[0].tuesday", is(false)))
|
(contentType))
|
||||||
.andExpect(jsonPath("$[0].wednesday", is(false))).andExpect(jsonPath("$[0].thursday", is(false)))
|
.andExpect(jsonPath("$", hasSize(2)))
|
||||||
.andExpect(jsonPath("$[0].friday", is(false))).andExpect(jsonPath("$[0].saturday", is(true)))
|
.andExpect(jsonPath("$[0].name", is("John")))
|
||||||
.andExpect(jsonPath("$[0].sunday", is(true)));
|
.andExpect(jsonPath("$[0].address.address", is("Fake Street 1")))
|
||||||
|
.andExpect(jsonPath("$[0].address.country", is("Spain")))
|
||||||
|
.andExpect(jsonPath("$[1].name", is("Lisa")))
|
||||||
|
.andExpect(jsonPath("$[1].address.address", is("Real Street 1")))
|
||||||
|
.andExpect(jsonPath("$[1].address.country", is("Germany")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue