parent
ed70f6b338
commit
64c2ef150e
|
@ -0,0 +1,7 @@
|
||||||
|
=========
|
||||||
|
|
||||||
|
## Guava 21
|
||||||
|
|
||||||
|
**Important**: Guava 21.0 requires Java 8. If you need Java 6, 7 or Android compatibility, use Guava 20.0 for now. Guava 22.0 and on will introduce a Java 6/Android compatible backport of Guava that includes all of the latest changes that don't require Java 8.
|
||||||
|
|
||||||
|
Article 1 : Introduction to Guava21 common.collect package.
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>com.baeldung.guava</groupId>
|
||||||
|
<artifactId>tutorial</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.8</source>
|
||||||
|
<target>1.8</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>21.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- https://mvnrepository.com/artifact/junit/junit -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.11</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.baeldung.guava.tutorial;
|
||||||
|
|
||||||
|
import com.google.common.collect.Comparators;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ComparatorsExamples {
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
|
||||||
|
List<Integer> integers = Arrays.asList(1,2,3,4,4,6,7,8,9,10);
|
||||||
|
//This will return true
|
||||||
|
boolean isInAscendingOrder = Comparators.isInOrder(integers, new AscedingOrderComparator());
|
||||||
|
|
||||||
|
System.out.println(isInAscendingOrder);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AscedingOrderComparator implements Comparator<Integer> {
|
||||||
|
@Override
|
||||||
|
public int compare(Integer o1, Integer o2) {
|
||||||
|
return o1.compareTo(o2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package com.baeldung.guava.tutorial;
|
||||||
|
|
||||||
|
import com.google.common.collect.Streams;
|
||||||
|
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class ConcatStreams {
|
||||||
|
public static Stream concatStreams(Stream stream1, Stream stream2, Stream stream3){
|
||||||
|
return Streams.concat(stream1,stream2,stream3);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.baeldung.guava.tutorial;
|
||||||
|
|
||||||
|
import com.google.common.collect.Interner;
|
||||||
|
import com.google.common.collect.Interners;
|
||||||
|
|
||||||
|
import static com.google.common.collect.Interners.newBuilder;
|
||||||
|
|
||||||
|
public class InternerBuilderExample {
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
Interner<Integer> interners = Interners.<Integer>newBuilder()
|
||||||
|
.concurrencyLevel(2)
|
||||||
|
.strong()
|
||||||
|
.<Integer>build();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.baeldung.guava.tutorial;
|
||||||
|
|
||||||
|
import com.google.common.collect.MoreCollectors;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class MoreCollectorsExample {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
List<Integer> numbers = Arrays.asList(1);
|
||||||
|
Optional<Integer> number = numbers.stream()
|
||||||
|
.map(e -> e * 2)
|
||||||
|
.collect(MoreCollectors.toOptional());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.baeldung.guava.tutorial;
|
||||||
|
|
||||||
|
import com.google.common.collect.Streams;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.DoubleStream;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.LongStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class StreamsUtility {
|
||||||
|
|
||||||
|
public static void main(String[] args){
|
||||||
|
|
||||||
|
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,18,19,20);
|
||||||
|
//Using Collection
|
||||||
|
Stream<Integer> streamFromCollection = Streams.stream(numbers);
|
||||||
|
//Using Iterator
|
||||||
|
Stream<Integer> streamFromIterator = Streams.stream(numbers.iterator());
|
||||||
|
//Using Iterable
|
||||||
|
Stream<Integer> streamFromIterable = Streams.stream((Iterable<Integer>) numbers);
|
||||||
|
//Using Optional
|
||||||
|
Stream<Integer> streamFromOptional = Streams.stream(Optional.of(1));
|
||||||
|
//Using OptionalLong to LongStream
|
||||||
|
LongStream streamFromOptionalLong = Streams.stream(OptionalLong.of(1));
|
||||||
|
//Using OptionalInt to IntStream
|
||||||
|
IntStream streamFromOptionalInt = Streams.stream(OptionalInt.of(1));
|
||||||
|
//Using OptionalDouble to DoubleStream
|
||||||
|
DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0));
|
||||||
|
|
||||||
|
Stream<Integer> concatenatedStreams = Streams.concat(streamFromCollection,streamFromIterable,streamFromIterator);
|
||||||
|
|
||||||
|
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
|
||||||
|
//This will return 10
|
||||||
|
Optional<Integer> lastItem = Streams.findLast(integers.stream());
|
||||||
|
|
||||||
|
Streams.zip(
|
||||||
|
Stream.of("candy", "chocolate", "bar"),
|
||||||
|
Stream.of("$1", "$2","$3"),
|
||||||
|
(arg1, arg2) -> arg1 + ":" + arg2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
import com.google.common.collect.Comparators;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.ToDoubleFunction;
|
||||||
|
import java.util.function.ToIntFunction;
|
||||||
|
import java.util.function.ToLongFunction;
|
||||||
|
|
||||||
|
public class ComparatorsUnitTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isInOrderTest(){
|
||||||
|
|
||||||
|
List<Integer> numbers = Arrays.asList(1,2,3,4,4,6,7,8,9,10);
|
||||||
|
|
||||||
|
boolean isInAscendingOrder = Comparators.isInOrder(numbers, new AscendingOrderComparator<Number>());
|
||||||
|
|
||||||
|
Assert.assertTrue(isInAscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isInStrictOrderTest(){
|
||||||
|
|
||||||
|
List<Integer> numbers = Arrays.asList(1,2,3,4,3,6,7,8,9,10);
|
||||||
|
|
||||||
|
boolean isInAscendingOrder = Comparators.isInOrder(numbers, new AscendingOrderComparator<Number>());
|
||||||
|
|
||||||
|
Assert.assertFalse(isInAscendingOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private class AscendingOrderComparator<I extends Number> implements Comparator<Integer>{
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(Integer o1, Integer o2) {
|
||||||
|
return o1.compareTo(o2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<Integer> reversed() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<Integer> thenComparing(Comparator<? super Integer> other) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <U> Comparator<Integer> thenComparing(Function<? super Integer, ? extends U> keyExtractor, Comparator<? super U> keyComparator) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <U extends Comparable<? super U>> Comparator<Integer> thenComparing(Function<? super Integer, ? extends U> keyExtractor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<Integer> thenComparingInt(ToIntFunction<? super Integer> keyExtractor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<Integer> thenComparingLong(ToLongFunction<? super Integer> keyExtractor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<Integer> thenComparingDouble(ToDoubleFunction<? super Integer> keyExtractor) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
import com.google.common.collect.Streams;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.DoubleStream;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.LongStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class GauavaStreamsTests {
|
||||||
|
|
||||||
|
List<Integer> numbers;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp(){
|
||||||
|
numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10,11,11,12,13,14,15,16,17,18,19,20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithCollection(){
|
||||||
|
//Deprecated API to create stream from collection
|
||||||
|
Stream streamFromCollection = Streams.stream(numbers);
|
||||||
|
|
||||||
|
//Assert.assertNotNull(streamFromCollection);
|
||||||
|
StreamUtility.assertStreamEquals(streamFromCollection, numbers.stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithIterable(){
|
||||||
|
Iterable<Integer> numbersIterable = (Iterable<Integer>) numbers;
|
||||||
|
|
||||||
|
Stream streamFromIterable = Streams.stream(numbersIterable);
|
||||||
|
|
||||||
|
Assert.assertNotNull(streamFromIterable);
|
||||||
|
StreamUtility.assertStreamEquals(streamFromIterable, numbers.stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithIterator(){
|
||||||
|
Iterator<Integer> numbersIterator = numbers.iterator();
|
||||||
|
|
||||||
|
Stream streamFromIterator = Streams.stream(numbersIterator);
|
||||||
|
|
||||||
|
Assert.assertNotNull(streamFromIterator);
|
||||||
|
StreamUtility.assertStreamEquals(streamFromIterator, numbers.stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithOptional(){
|
||||||
|
|
||||||
|
Stream streamFromOptional = Streams.stream(Optional.of(1));
|
||||||
|
|
||||||
|
Assert.assertNotNull(streamFromOptional);
|
||||||
|
Assert.assertEquals(streamFromOptional.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithOptionalLong(){
|
||||||
|
|
||||||
|
LongStream streamFromOptionalLong = Streams.stream(OptionalLong.of(1));
|
||||||
|
|
||||||
|
Assert.assertNotNull(streamFromOptionalLong);
|
||||||
|
Assert.assertEquals(streamFromOptionalLong.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithOptionalInt(){
|
||||||
|
|
||||||
|
IntStream streamFromOptionalInt = Streams.stream(OptionalInt.of(1));
|
||||||
|
|
||||||
|
//Assert.assertNotNull(streamFromOptionalInt);
|
||||||
|
Assert.assertEquals(streamFromOptionalInt.count(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createStreamsWithOptionalDouble(){
|
||||||
|
|
||||||
|
DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0));
|
||||||
|
|
||||||
|
//Assert.assertNotNull(streamFromOptionalDouble);
|
||||||
|
Assert.assertEquals(streamFromOptionalDouble.count(), 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void concatStreamsOfSameType(){
|
||||||
|
Stream oddNumbers = Arrays.asList(1,3,5,7,9,11,13,15,17,19).stream();
|
||||||
|
Stream evenNumbers = Arrays.asList(2,4,6,8,10,12,14,16,18,20).stream();
|
||||||
|
|
||||||
|
Stream combinedStreams = Streams.concat(oddNumbers,evenNumbers);
|
||||||
|
|
||||||
|
//Assert.assertNotNull(combinedStreams);
|
||||||
|
StreamUtility.assertStreamEquals(combinedStreams, Stream.concat(oddNumbers, evenNumbers));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void concatStreamsOfTypeLongStream(){
|
||||||
|
LongStream firstTwenty = LongStream.range(1,20);
|
||||||
|
LongStream nextTwenty = LongStream.range(21,40);
|
||||||
|
|
||||||
|
LongStream combinedStreams = Streams.concat(firstTwenty,nextTwenty);
|
||||||
|
|
||||||
|
Assert.assertNotNull(combinedStreams);
|
||||||
|
StreamUtility.assertStreamEquals(combinedStreams, LongStream.concat(firstTwenty, nextTwenty));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void concatStreamsOfTypeIntStream(){
|
||||||
|
IntStream firstTwenty = IntStream.range(1,20);
|
||||||
|
IntStream nextTwenty = IntStream.range(21,40);
|
||||||
|
|
||||||
|
IntStream combinedStreams = Streams.concat(firstTwenty,nextTwenty);
|
||||||
|
|
||||||
|
Assert.assertNotNull(combinedStreams);
|
||||||
|
StreamUtility.assertStreamEquals(combinedStreams, IntStream.concat(firstTwenty, nextTwenty));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void findLastOfStream(){
|
||||||
|
Optional<Integer> lastElement = Streams.findLast(numbers.stream());
|
||||||
|
|
||||||
|
Assert.assertNotNull(lastElement.get());
|
||||||
|
Assert.assertEquals(lastElement.get(), numbers.get(20));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mapWithIndexTest(){
|
||||||
|
Stream stringSream = Stream.of("a","b","c");
|
||||||
|
|
||||||
|
Stream<String> mappedStream = Streams.mapWithIndex(stringSream,(str,index) -> str +":"+ index);
|
||||||
|
|
||||||
|
//Assert.assertNotNull(mappedStream);
|
||||||
|
Assert.assertEquals(mappedStream.findFirst().get(), "a:0");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void streamsZipTest(){
|
||||||
|
Stream stringSream = Stream.of("a","b","c");
|
||||||
|
Stream intStream = Stream.of(1,2,3);
|
||||||
|
Stream<String> mappedStream = Streams.zip(stringSream,intStream, (str,index) -> str +":"+ index);
|
||||||
|
|
||||||
|
//Assert.assertNotNull(mappedStream);
|
||||||
|
Assert.assertEquals(mappedStream.findFirst().get(), "a:1");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import com.google.common.collect.Interner;
|
||||||
|
import com.google.common.collect.Interners;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class InternBuilderUnitTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void interBuilderTest(){
|
||||||
|
|
||||||
|
Interner<Integer> interners = Interners.<Integer>newBuilder()
|
||||||
|
.concurrencyLevel(2)
|
||||||
|
.strong()
|
||||||
|
.<Integer>build();
|
||||||
|
|
||||||
|
Assert.assertNotNull(interners);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
import com.google.common.collect.MoreCollectors;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class MoreCollectorsUnitTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toOptionalTest(){
|
||||||
|
|
||||||
|
List<Integer> numbers = Arrays.asList(1);
|
||||||
|
|
||||||
|
Optional<Integer> number = numbers.stream()
|
||||||
|
.map( e -> e*2)
|
||||||
|
.collect(MoreCollectors.toOptional());
|
||||||
|
|
||||||
|
Assert.assertEquals(number.get(),new Integer(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void onlyElementTest(){
|
||||||
|
List<Integer> numbers = Arrays.asList(1);
|
||||||
|
|
||||||
|
Integer number = numbers.stream()
|
||||||
|
.map( e -> e*2)
|
||||||
|
.collect(MoreCollectors.onlyElement());
|
||||||
|
|
||||||
|
Assert.assertEquals(number,new Integer(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.stream.DoubleStream;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.LongStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class StreamUtility {
|
||||||
|
|
||||||
|
public static <T> boolean assertStreamEquals(Stream<T> stream1, Stream<T> stream2){
|
||||||
|
|
||||||
|
Iterator<T> iterator1 = stream1.iterator();
|
||||||
|
Iterator<T> iterator2 = stream2.iterator();
|
||||||
|
|
||||||
|
while (iterator1.hasNext()){
|
||||||
|
Assert.assertEquals(iterator1.next(), iterator2.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertFalse(iterator2.hasNext());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean assertStreamEquals(LongStream stream1, LongStream stream2) {
|
||||||
|
|
||||||
|
Iterator iterator1 = stream1.iterator();
|
||||||
|
Iterator iterator2 = stream2.iterator();
|
||||||
|
|
||||||
|
while (iterator1.hasNext()){
|
||||||
|
Assert.assertEquals(iterator1.next(), iterator2.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertFalse(iterator2.hasNext());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean assertStreamEquals(DoubleStream stream1, DoubleStream stream2) {
|
||||||
|
|
||||||
|
Iterator iterator1 = stream1.iterator();
|
||||||
|
Iterator iterator2 = stream2.iterator();
|
||||||
|
|
||||||
|
while (iterator1.hasNext()){
|
||||||
|
Assert.assertEquals(iterator1.next(), iterator2.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertFalse(iterator2.hasNext());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean assertStreamEquals(IntStream stream1, IntStream stream2) {
|
||||||
|
|
||||||
|
Iterator iterator1 = stream1.iterator();
|
||||||
|
Iterator iterator2 = stream2.iterator();
|
||||||
|
|
||||||
|
while (iterator1.hasNext()){
|
||||||
|
Assert.assertEquals(iterator1.next(), iterator2.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
Assert.assertFalse(iterator2.hasNext());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue