From 1e9b6dd159e598edf87435ef15562e4bdfeed526 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Tue, 27 Apr 2021 13:19:04 +0900 Subject: [PATCH 01/18] =?UTF-8?q?docs:=EC=9E=90=EB=B0=94=20=EC=BB=AC?= =?UTF-8?q?=EB=A0=89=EC=85=98=20=ED=94=84=EB=A0=88=EC=9E=84=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...10\354\236\204\354\233\214\355\201\254.md" | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 "10week/\354\236\220\353\260\224 \354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204\354\233\214\355\201\254.md" diff --git "a/10week/\354\236\220\353\260\224 \354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204\354\233\214\355\201\254.md" "b/10week/\354\236\220\353\260\224 \354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204\354\233\214\355\201\254.md" new file mode 100644 index 00000000..87226924 --- /dev/null +++ "b/10week/\354\236\220\353\260\224 \354\273\254\353\240\211\354\205\230 \355\224\204\353\240\210\354\236\204\354\233\214\355\201\254.md" @@ -0,0 +1,144 @@ +--- + +# 컬렉션 프레임 워크 (JCF ( Java Collection Framework )) + +--- + +## 컬렉션 프레임 워크란? + +- 컬렉션 프레임 워크란? + +- 컬렉션 프레임 워크란 여러 요소를 담을 수 있는 자료구조를 의미하며 배열과 유사하다고 생각 할 수 있지만 다른 특성을 가진다. +- 가장 대표적인 차이점은 배열은 크기가 고정되어있지만 컬렉션은 그렇지 않다. 크기가 고정되어있지 않아 배열의 고정된 크기로 생길수있는 문제점을 해결해 줄수 있다. + - ex) 배열의 크기 고정으로 인해 생길수 있는 처음에 정한 크기보다 더 큰 데이터를 넣을 시 오류가 발생하고, 데이터 삭제시 인덱스는 비지만 메모리값은 낭비가 되는 문제점들을 보완 할수 있다. +- 대표적으로는 List, Map, Stack, Queue 등이 있다. + +**프레임 워크의 구성 위치** + +- 컬렉션 인터페이스 : 모든 컬렉션 인터페이스는 java.util 패키지에 포함 되어있다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0ce0c0ee-aad9-46df-8dbb-18169c811db6/_2021-04-27__11.13.18.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0ce0c0ee-aad9-46df-8dbb-18169c811db6/_2021-04-27__11.13.18.png) + +- 컬렉션 클래스 : 모든 컬렉션 클래스는 java.util or java.utl.concurrent 패키지에 포함된다. (인터페이스에 대한 구현 클래스) +- 컬렉션 기능 : 검색, 정렬, 셔플등의 기능을 지원. + +--- + +## 컬렉션 인터페이스 + +- 컬렉션 인터페이스 들은 제네릭으로 구현 하여 컴파일시 체크 단계를 거치게 되어 에러를 줄일수있다. +- 컬렉션 프레임워크의 대표적 인터페이스 + - List + - Set + - Map + +List와 Set은 Collection 인터페이스에서 정의 하고 있으나 Map은 값으로 이루어져있어 별도로 구현된다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a26287fa-0b1c-447f-93d2-f6ff1fe6d3fd/_2021-04-27__11.49.44.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a26287fa-0b1c-447f-93d2-f6ff1fe6d3fd/_2021-04-27__11.49.44.png) + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2bec1033-b4b3-4592-81d2-38dcfa120e08/_2021-04-27__11.51.33.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2bec1033-b4b3-4592-81d2-38dcfa120e08/_2021-04-27__11.51.33.png) + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1b75a0b8-2891-42e9-811b-558d1c96e578/_2021-04-27__12.05.44.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/1b75a0b8-2891-42e9-811b-558d1c96e578/_2021-04-27__12.05.44.png) + +💁 **Collection 인터페이스 그룹** + +- 직접 구현을 하지 않고 메서드만 포함하고 있다. + - boolean add(E e) + - boolean addAll(Collection c) + - void clear() + - boolean contains(Object o) + - boolean containsAll(Collection c) + - boolean equals(Object o) + - int hashCode() + - boolean isEmpty() + - Iterator iterator() + - int size() + + 등등.. + +(각 메소드에 대한 자세한 설명은 생략 하겠습니다. 이름만 보고도 무슨 역할을 할지 알수있는 메소드명을 지을수 있도록 노력하자👍) + +💁 **List 인터페이스 그룹** + +- 컬렉션 프레임 워크를 상속 받고있는 List 컬렉션은 객체를 일렬로 늘어 놓은 배열과 유사한 구조를 가지고 있으며 검색, 삭제등의 기능을 제공한다. +- List 컬렉션을 구성하는 대표적인 클래스 (ArrayList, LinkedList, Vector) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a7cd2226-ace9-48b0-9939-39425125ab8a/_2021-04-27__12.04.23.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a7cd2226-ace9-48b0-9939-39425125ab8a/_2021-04-27__12.04.23.png) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/662caacb-6966-47d3-bee5-29f5731fb64a/_2021-04-27__12.05.01.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/662caacb-6966-47d3-bee5-29f5731fb64a/_2021-04-27__12.05.01.png) + +- 대표적인 메소드 + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/28d0bdca-ec79-4792-8dc1-03cc0ab7094d/_2021-04-27__12.16.15.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/28d0bdca-ec79-4792-8dc1-03cc0ab7094d/_2021-04-27__12.16.15.png) + +💁 **Set 인터페이스 그룹** + +- 리스트 구조는 순서가 있는 선형구조로 이루어져 있으나 Set 은 그렇지 않다 따라서 인덱스를 이용해 객체를 검색해 가져오는 메소드가 존재 하지 않는다. 대신 반복자인 Iterator를 제공한다. (List도 Iterator 지원) +- 또한 중복 된 값을 저장 할 수 없으며 Null 값도 하나만 저장 할수 있다. +- Set 인터페이스를 상속하는 대표적인 클래스는 HashSet 과 TreeSet 이 있다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3a9f14a9-3ded-4a4a-b4cd-a91076009ce5/_2021-04-27__12.11.42.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/3a9f14a9-3ded-4a4a-b4cd-a91076009ce5/_2021-04-27__12.11.42.png) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/009cf03a-f594-40b0-8141-482c801a7644/_2021-04-27__12.13.46.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/009cf03a-f594-40b0-8141-482c801a7644/_2021-04-27__12.13.46.png) + +- 대표적인 메소드 + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c90386c1-6864-4d2a-a5f4-2f92ede36b48/_2021-04-27__12.14.36.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c90386c1-6864-4d2a-a5f4-2f92ede36b48/_2021-04-27__12.14.36.png) + +--- + +💁 **Map 인터페이스** + +- Map은 Key값과 Value 값을 매핑 하여 사용해 Collection과 별도로 구현이 되어있으며, Set과 동일하게 중복값이 존재 할수 없다. +- Map 인터페이스로 구현된 클래스 + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9c09e86a-99e1-46bb-850d-24739bf8dbd0/_2021-04-27__12.22.15.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/9c09e86a-99e1-46bb-850d-24739bf8dbd0/_2021-04-27__12.22.15.png) + +- Map의 주요 메소드 + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ad88ad29-76de-4f23-90a0-734af25d54c3/_2021-04-27__12.32.38.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/ad88ad29-76de-4f23-90a0-734af25d54c3/_2021-04-27__12.32.38.png) + +--- + +## 컬렉션 알고리즘 + +- 모든 컬렉션의 알고리즘을 담당하며 Static으로 구현된 유틸리티 클래스이다. 주요 메소드는 (Sort, BinarySearch, get, Reverse, Swap, Copy, Min, Max 등이 있다.) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/56a17939-ba03-45c4-b3a4-36d43518785c/_2021-04-27__1.01.49.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/56a17939-ba03-45c4-b3a4-36d43518785c/_2021-04-27__1.01.49.png) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4dc488a8-8bce-41b8-8269-ac80d0044b13/_2021-04-27__1.01.56.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4dc488a8-8bce-41b8-8269-ac80d0044b13/_2021-04-27__1.01.56.png) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2d268287-0afa-41cc-b0ff-7f0156b6b71a/_2021-04-27__1.02.05.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2d268287-0afa-41cc-b0ff-7f0156b6b71a/_2021-04-27__1.02.05.png) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/55bfdd8f-a04a-4043-949d-1fecd655b6b2/_2021-04-27__1.02.17.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/55bfdd8f-a04a-4043-949d-1fecd655b6b2/_2021-04-27__1.02.17.png) + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b28b80d1-a14f-4009-a77c-c56225f2cfb5/_2021-04-27__1.02.26.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/b28b80d1-a14f-4009-a77c-c56225f2cfb5/_2021-04-27__1.02.26.png) + +--- + +## 컬렉션 프레임워크의 모범 사례 + +필요에 따라 상황에 맞는 컬렉션을 선택해야 된다. + +- 크기(size)가 고정되어 있다면 ArrayList보다 **Array**를 사용하라. +- 맵에 삽입된 순서대로 iterate를 하고 싶으면 **TreeMap**을 사용하는 것이 좋다. +- 중복을 허용하고 싶지 않으면 **Set**을 사용하면 된다. +- 몇몇 컬렉션 클래스들을 초기 용량을 지정할 수 있다. 만약 저장할 요소들의 사이즈를 알 경우에 **초기 용량**을 지정함으로써 rehashing이나 resizing이 일어나는 것을 회피할 수 있다. +- 코드를 작성할 때, 구현 클래스가 아닌 **인터페이스**를 기반으로 작성해야 나중에 구현체를 변경할 때 코드를 재작성하는 수고를 줄일 수 있다. +- 런타임에 발생할 수 있는 ClassCastException을 회피하려면 항상 **제네릭(Generics)을** 사용해서 type-safety 한 상태를 유지하라. +- 맵에 키를 사용할 때 JDK에서 제공하는 **immutable** 클래스를 사용하여 사용자 클래스에서 hashCode()와 equals() 구현할 필요가 없게 하라 +- 읽기 전용 및 동기화, 빈 컬렉션 등을 만들 때는 자신만의 구현으로 생성하지 말고 Collections에서 제공하는 **유틸리티 클래스**를 사용하라. 이는 코드 재사용성을 높여주고 안정적이며 유지보수 비용을 줄여 준다. + +[https://gbsb.tistory.com/247](https://gbsb.tistory.com/247) ( 작성자 분 ) + +--- + + + +## Reference + +[https://gbsb.tistory.com/247](https://gbsb.tistory.com/247) + +[https://coding-factory.tistory.com/550](https://coding-factory.tistory.com/550) + +[https://docs.oracle.com/javase/9/docs/api/java/util/List.html](https://docs.oracle.com/javase/9/docs/api/java/util/List.html) \ No newline at end of file From fb5223d883f89bc2df77d7aa95d45f02488d58fe Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Wed, 28 Apr 2021 12:49:02 +0900 Subject: [PATCH 02/18] =?UTF-8?q?docs:=EC=8A=A4=ED=8A=B8=EB=A6=BC=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...0\353\246\274 \354\240\225\353\246\254.md" | 113 ++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 "10week/\354\212\244\355\212\270\353\246\274 \354\240\225\353\246\254.md" diff --git "a/10week/\354\212\244\355\212\270\353\246\274 \354\240\225\353\246\254.md" "b/10week/\354\212\244\355\212\270\353\246\274 \354\240\225\353\246\254.md" new file mode 100644 index 00000000..d0e26ef4 --- /dev/null +++ "b/10week/\354\212\244\355\212\270\353\246\274 \354\240\225\353\246\254.md" @@ -0,0 +1,113 @@ +--- + +# Stream의 특징 정리 (map, filter, sorted, distinct, limit. foreach) + +--- + +## 자바 8 스트림? + +💁 자바 8에서 추가된 스트림은 람다식을 활용한 기술 중 하나로 테이터의 흐름이라는 뜻을 가지고 있다. + +💁 스트림이란 간단하게 설명하면 자바의 컬렉션의 반복을 기존의 반복문 보다 효율적으로 처리하는 방식이라고 생각하면 이해가 쉽다. 스트림 이용시 따로 멀티 스레드 코드를 구현하지 않아도 병렬로 데이터가 처리가 된다. + +💁 스트림은 선언형 코드로 구현이 가능하다. 루프, if 등의 조건문을 이용해 어떻게 동작할지 지정하지 않아도 선언형 방식으로 동작을 지정할수 있어 변하는 요구사항에 효율적으로 대응이 가능하다. 따라서 람다식을 통해 기존 코드의 중복을 줄이고 특정 조건을 필터링 하는 코드를 쉽게 구현이 가능하다. + +💁 위와 같은 특징으로 인해 Sort, Filter, Map 등의 빌딩 블록 연산을 이용해 복잡한 데이터 처리에 유용하며 가독성을 해치지 않는다. + +- 요약 + +--- + +## 스트림과 컬렉션 + +💁 자바의 기존 컬렉션과 스트림 모두 순차적으로 데이터를 저장하는 형식의 자료구조 인터페이스를 제공한다. 하지만 이 둘의 가장 큰 차이점은 언제 계산하느냐 이다. + +🤔 컬렉션 : 자료구조가 포함하는 모든 값을 메모리에 저장 = 즉 컬렉션에 추가 되기전에 계산이 되어야 한다. + +🤔 스트림 : 이론적으로 요청 할때만 요소를 계산하는 고정된 자료구조( 스트림에 자료를 추가하거나, 삭제 불가능 ) 스트림은 요청하는 값만 스트림에서 추출을 하는데 이는 사용자는 알 수 없다. 결과적으로 생산자와 소비자관계를 형성하게 된다. + +🖍 **하나의 스트림은** **스트림은 한번만 사용 가능하다.** + +- 반복자와 동일하게 스트림도 한번만 탐색 할수 있으며 다시 사용 하고 싶다면 새로운 스트림을 만들어야 한다. 또 스트림은 시간적으로 흩어진 값의 집합으로 간주 할수 있다. + +--- + +## 스트림 연산 + +🖍 **중간 연산** + +- filter  나 sorted 같은 중간 연산은 연산 후에 다른 스트림을 반환한다. 이 특성을 이용해 연속해서 질의를 이어 나갈수 있다. 중간 연산은 중요한 특징은 Lazy한 특성을 갖고 있어 단말 연산을 스트림 파이프 라인에 실행하기 전까지는 어떤 연산도 수행도 하지 않는다. 그저 합쳐 놓고 최종 연산으로 한번에 처리 한다. + +🖍 **최종 연산** + +- 최종 연산은 파이프 라인에서 결과를 도출하고 스트림 이외의 결과가 반환 된다. + +☝️ **생성하기** + +- 보통 배열을 이용해 스트림을 만들지만 이외의 방식으로도 스트림을 생성이 가능하다. + +**배열 스트림** + +- 배열은 [Array.stream](http://array.stream) 메소드를 이용해 생성을 한다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c1ff0f64-78d9-4232-becf-1601432db851/_2021-04-28__11.31.17.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c1ff0f64-78d9-4232-becf-1601432db851/_2021-04-28__11.31.17.png) + +**컬렉션 스트림** + +- 컬렉션 타입을 이용해서도 스트림을 생성 가능하다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c030af2b-17b3-4162-a03b-1595e93f3068/_2021-04-28__11.28.35.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c030af2b-17b3-4162-a03b-1595e93f3068/_2021-04-28__11.28.35.png) + +☝️**Filtering** + +- 필터는 스트림 내 요소들을 하나씩 평가해 걸러내는 작업으로 boolean을 리턴하게 된다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/58492cb9-7b22-4ef6-9486-832ead9f52db/_2021-04-28__11.38.45.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/58492cb9-7b22-4ef6-9486-832ead9f52db/_2021-04-28__11.38.45.png) + + - 위 코드는 요소중에 동현이라는 값을 가진 요소를 제외 하고 나머지는 필터링 하는 코드이다. + - collect을 이용해 필터링을 하고 결과를 리스트로 반환 해준다. + +☝️ **Mapping** + +- 특정 객체에서 특정 데이터를 선택하는 작업은 데이터 처리과정에서 자주 수행 되는 연산이다. 스트림 에서는 map 과 flatMap을 제공한다. +- Map : 스트림의 각 요소에 함수 적용 + - 각 요소에 적용 돼 새로운 요소로 매핑이 된다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7368d742-5990-4a72-ae87-088dfe3defec/_2021-04-28__12.03.14.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/7368d742-5990-4a72-ae87-088dfe3defec/_2021-04-28__12.03.14.png) + + - 위 코드는 carNames 라는 string 배열의 값을 이용해 Car객체로 생성해주는 매핑이다. +- flatMap : 중간 중첩 구조를 한단계 제거 하고 단일 컬렉션으로 만들어 주는 역할을 한다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d87f0f85-808c-456e-99f4-22fd5b967b82/_2021-04-28__12.23.02.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d87f0f85-808c-456e-99f4-22fd5b967b82/_2021-04-28__12.23.02.png) + +☝️ **Sorting** + +- 스트림에서 sort는 스트림 아이템을 정렬후 새로운 스트림을 생성한다. 다른 정렬과 마찬가지로 comparator 를 이용하며 인자 없이 그냥 호출시 오름차순으로 정렬 된다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0b068347-4fb2-4b89-9905-aa61607f281e/_2021-04-28__12.35.35.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/0b068347-4fb2-4b89-9905-aa61607f281e/_2021-04-28__12.35.35.png) + +- 인자를 넘기는 경우에는 comparator 를 이용하게 된다. String 의 경우에는 Comparable 인터페이스가 구현이 되어있어 Comparator 를 바로 사용할수있지만 그렇지 않은경우에는 직접 정의를 해야한다. + +☝️ **Distinct** + +- 사전적의미로는 뚜렷한, 분명한 이란 의미를 가지고 있는데 이는 스트림에서 중복제거를 도와주는 역할을 한다. 즉 스트림에서 사용시 중복된 요소를 모두 제거 하고 새로운 스트림을 생성해준다. 중복된 요소의 판단 기준은 Object.equals(Object) 값이다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e78bd6eb-b284-4954-935b-241db29c77ec/_2021-04-28__12.42.46.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e78bd6eb-b284-4954-935b-241db29c77ec/_2021-04-28__12.42.46.png) + +☝️**Limit** + +- Limit는 어떤 스트림에서 일정 개수 만큼 가져와 새로운 스트림을 생성하는데 사용 방법은 Stream.limit(숫자) 로 숫자만큼 데이터를 셀렉하고 스트림으로 생성하게 된다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2a2929a-96b3-435e-8a17-abf793293b49/_2021-04-28__12.46.02.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c2a2929a-96b3-435e-8a17-abf793293b49/_2021-04-28__12.46.02.png) + +🔍 forEach에 대해서는 다음 정리에서 다루도록 하겠습니다. + +--- + +## Reference + +[https://futurecreator.github.io/2018/08/26/java-8-streams/](https://futurecreator.github.io/2018/08/26/java-8-streams/) + +[https://12bme.tistory.com/461](https://12bme.tistory.com/461) + +[https://codechacha.com/ko/java8-stream-limit-skip/](https://codechacha.com/ko/java8-stream-limit-skip/) \ No newline at end of file From 63ec72145aa369e5fef49bd302d419794f764128 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Fri, 30 Apr 2021 21:31:09 +0900 Subject: [PATCH 03/18] docs:collection.foreach vs stream.foreach --- .../collection.foreach vs stream.foreach.md | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 10week/collection.foreach vs stream.foreach.md diff --git a/10week/collection.foreach vs stream.foreach.md b/10week/collection.foreach vs stream.foreach.md new file mode 100644 index 00000000..7a427e70 --- /dev/null +++ b/10week/collection.foreach vs stream.foreach.md @@ -0,0 +1,62 @@ +--- + +# **Collection.forEach 와 Stream.forEach 의 차이** + +--- + +## Stream의 foreach와 for-loop는 다르다. + +- stream 은 java8 부터 람다와 함께 제공된 방법이며 컬렉션 요소를 하나씩 참조해 함수형 인터페이스를 통한 반복적 처리를 가능하게 해준다. + +- 이에 for문을 stream으로 대신해 처리하는 경우가 빈번하다. + +**하지만 무턱대고 아무곳에서나 for문을 stream으로 바꿔 구현하는 행위는 옳지 않다.** + +- 물론 Stream을 사용하면 가독성이 높아져 코드 이해도가 높아진다. 하지만 다음 예시에서는 사용을 다시 생각해 봐야할 필요가 있다. + +## 🤔 **만약 Stream의 모든 요소를 도는 forEach를 사용시 종료 조건이 있는 경우에는 어떡할까?** + +- 일단 Stream 에서 강제적으로 루프를 탈출 할 수 있는 방법은 없다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/82dc64e7-1599-473e-a586-8f92e1e40e1b/_2021-04-29__11.11.17.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/82dc64e7-1599-473e-a586-8f92e1e40e1b/_2021-04-29__11.11.17.png) + +- 다음 코드의 결과를 보면 같은 결과 값을 내지만 기존의 for 문에서는 50까지 수행이되면 이후는 수행 되지 않고 반복문이 종료가 되지만 stream 을 사용한 아래의 코드는 return이후 코드만 처리되지 않을뿐 50이 넘어서도 모든 조건을 확인 후에 종료하게 된다. + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/32e7a32a-0778-423e-acb6-bff49ad79166/_2021-04-29__11.12.21.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/32e7a32a-0778-423e-acb6-bff49ad79166/_2021-04-29__11.12.21.png) + +- 다음과 같이 같은 조건문을 가지더라도 모든 조건을 다 확인하는 stream에서는 중간에 종료가 불가능 하여 비효율 적이다. forEach 연산의 올바른 사용법인 Filter 를 쓰더라도 stream은 지연 연산을 지원 하기 때문에 100번 모두를 검사하게 된다. +- 또한 forEach연산을 최종 연산중 가장 기능이 적고 Stream 스럽지 못하므로 print 문을 사용할때만 쓰자. + +--- + +## Collection.forEach 와 Stream.forEach 의 차이점 + +![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2b59e6d0-45e5-489c-99af-ce367ebb60e0/_2021-04-29__11.46.29.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2b59e6d0-45e5-489c-99af-ce367ebb60e0/_2021-04-29__11.46.29.png) + +- 코드만 봤을 경우에는 그렇게 큰 차이는 없다. +- Collection.forEach의 경우 따로 객체를 생성하지 않고 forEach메소드를 호출하는데 Iterable 인터페이스를 상속하고 있기 때문이다. +- stream.forEach의 경우는 Collection 인터페이스의 메소드인 stream() 을 통해 stream 객체를 생성해야만 forEach 호출이 가능하다. +- 출력문을 봐도 별 차이가 없다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/dbed982b-2a70-4c9c-859c-ad6c93703462/_2021-04-29__12.07.44.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/dbed982b-2a70-4c9c-859c-ad6c93703462/_2021-04-29__12.07.44.png) + +- 하지만 동시성 부분에서는 차이가 있다. + +**동시성** + +- Collection.forEach의 경우는 중간 과정에 삭제하는 조건문을 넣어두고 수정을 감지하면 Exception을 터트리는 구조로 코드를 작성하면 변경과 동시에 Exception 을 터트린다. (ConcurrentModificationException) +- 반면 Stream.forEach의 경우에는 다르다 Collection 때 처럼 수정을 감지하는 코드를 작성해 놓으면 Stream 은 리스트를 모두 순회 하고 예외를 던진다. (NulPointerException) + +- Collection의 경우에는 Iterator을 사용하고 Stream은 spliterator을 사용한다. 아래의 [Collections.java](http://collections.java) 의 코드를 보면 Synchronized 키워드가 붙어 있다. 반면 stream에는 붙어있지 않다. + + ![https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d5d8eb35-1b32-4693-82e8-3dd59da18eba/_2021-04-29__12.28.13.png](https://s3-us-west-2.amazonaws.com/secure.notion-static.com/d5d8eb35-1b32-4693-82e8-3dd59da18eba/_2021-04-29__12.28.13.png) + +- 결론적으로 둘은 큰 차이가 없지만 단순 반복을 위한 forEach면 Stream사용보다 일반 collection 의 foreach사용을 권장한다. + +--- + +## Reference + +[https://woowacourse.github.io/javable/post/2020-05-14-foreach-vs-forloop/](https://woowacourse.github.io/javable/post/2020-05-14-foreach-vs-forloop/) + +[https://woowacourse.github.io/javable/post/2020-09-30-collection-stream-for-each/](https://woowacourse.github.io/javable/post/2020-09-30-collection-stream-for-each/) \ No newline at end of file From d6a404ef759f277a7fdda36d2343877ccd3ad5ed Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Fri, 30 Apr 2021 21:31:53 +0900 Subject: [PATCH 04/18] refactor:for -> stream --- 8week/racingcar/.gitignore | 21 ++ 8week/racingcar/build.gradle | 14 ++ 8week/racingcar/document/README.md | 84 ++++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes .../gradle/wrapper/gradle-wrapper.properties | 5 + 8week/racingcar/gradlew | 185 ++++++++++++++++++ 8week/racingcar/gradlew.bat | 104 ++++++++++ 8week/racingcar/settings.gradle | 2 + .../racingcar/src/main/java/Application.java | 7 + 8week/racingcar/src/main/java/domain/Car.java | 54 +++++ .../racingcar/src/main/java/domain/Cars.java | 52 +++++ .../src/main/java/domain/Number.java | 22 +++ .../src/main/java/service/RacingGame.java | 8 + .../java/service/RacingGameController.java | 33 ++++ .../racingcar/src/main/java/utils/Input.java | 37 ++++ .../src/main/java/utils/RandomUtils.java | 24 +++ 8week/racingcar/src/main/java/utils/View.java | 43 ++++ 8week/racingcar/src/test/java/StreamTest.java | 19 ++ 18 files changed, 714 insertions(+) create mode 100644 8week/racingcar/.gitignore create mode 100644 8week/racingcar/build.gradle create mode 100644 8week/racingcar/document/README.md create mode 100644 8week/racingcar/gradle/wrapper/gradle-wrapper.jar create mode 100644 8week/racingcar/gradle/wrapper/gradle-wrapper.properties create mode 100755 8week/racingcar/gradlew create mode 100644 8week/racingcar/gradlew.bat create mode 100644 8week/racingcar/settings.gradle create mode 100644 8week/racingcar/src/main/java/Application.java create mode 100644 8week/racingcar/src/main/java/domain/Car.java create mode 100644 8week/racingcar/src/main/java/domain/Cars.java create mode 100644 8week/racingcar/src/main/java/domain/Number.java create mode 100644 8week/racingcar/src/main/java/service/RacingGame.java create mode 100644 8week/racingcar/src/main/java/service/RacingGameController.java create mode 100644 8week/racingcar/src/main/java/utils/Input.java create mode 100644 8week/racingcar/src/main/java/utils/RandomUtils.java create mode 100644 8week/racingcar/src/main/java/utils/View.java create mode 100644 8week/racingcar/src/test/java/StreamTest.java diff --git a/8week/racingcar/.gitignore b/8week/racingcar/.gitignore new file mode 100644 index 00000000..76611b07 --- /dev/null +++ b/8week/racingcar/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar +/out/ +/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr \ No newline at end of file diff --git a/8week/racingcar/build.gradle b/8week/racingcar/build.gradle new file mode 100644 index 00000000..95df5f5c --- /dev/null +++ b/8week/racingcar/build.gradle @@ -0,0 +1,14 @@ +plugins { + id 'java' +} + +group 'org.example' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testCompile group: 'junit', name: 'junit', version: '4.12' +} diff --git a/8week/racingcar/document/README.md b/8week/racingcar/document/README.md new file mode 100644 index 00000000..80371684 --- /dev/null +++ b/8week/racingcar/document/README.md @@ -0,0 +1,84 @@ +# RacingCar 기능정리 + +--- +## Domain + +### Car +* 아는 것 + * 차의 이름 + * 차의 위치 + * 랜덤 범위 +* 하는 것 + * 차 이동 + * 이름 검증 (공백, 길이) + +### Cars +* 아는 것 + * 복수의 차 +* 하는 것 + * 차 전체 이동 + * 가장 멀리간 차의 위치 찾기 + * 우승자 찾기 + * 차 이름 중복 검증 + +### Number +* 아는 것 + * 숫자 값 +* 하는 것 + * 변수형 검 + +--- + +## Service + +### RacingCarGame +* 아는 것 +* 하는 것 + * 게임 시작 + +### RacingCarGameController +* 아는 것 +* 하는 것 + * 차 생성 + * count 생성 + * 경주 실행 + +--- + +## Utils + +### Input +* 아는 것 +* 하는 것 + * 숫자 입력 + * 문자 입력 + +### RandomUtils +* 아는 것 + * 랜덤 라이브러리 +* 하는 것 + * 범위 내의 랜덤값 생 + + +### View +* 아는 것 +* 하는 것 + * 거리 출력 + * 차 이름 출력 + * 우승자 출력 + + + +보장된 숫자 입력 + +보장된 문자 입력 + +보장된 숫자가 아닐 시 에러가 발생한다. + +자동차 이름 중복 제거 + +자동차 이름의 길이가 5이하 보장 + +범위내의 랜덤값 생성 보장 + +String 입력을 각 항목별 분리 \ No newline at end of file diff --git a/8week/racingcar/gradle/wrapper/gradle-wrapper.jar b/8week/racingcar/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 zcma&ObC74zk}X`WF59+k+qTVL*+!RbS9RI8Z5v&-ZFK4Nn|tqzcjwK__x+Iv5xL`> zj94dg?X`0sMHx^qXds{;KY)OMg#H>35XgTVfq6#vc9ww|9) z@UMfwUqk)B9p!}NrNqTlRO#i!ALOPcWo78-=iy}NsAr~T8T0X0%G{DhX~u-yEwc29WQ4D zuv2j{a&j?qB4wgCu`zOXj!~YpTNFg)TWoV>DhYlR^Gp^rkOEluvxkGLB?!{fD!T@( z%3cy>OkhbIKz*R%uoKqrg1%A?)uTZD&~ssOCUBlvZhx7XHQ4b7@`&sPdT475?*zWy z>xq*iK=5G&N6!HiZaD{NSNhWL;+>Quw_#ZqZbyglna!Fqn3N!$L`=;TFPrhodD-Q` z1l*=DP2gKJP@)cwI@-M}?M$$$%u~=vkeC%>cwR$~?y6cXx-M{=wdT4|3X(@)a|KkZ z`w$6CNS@5gWS7s7P86L<=vg$Mxv$?)vMj3`o*7W4U~*Nden}wz=y+QtuMmZ{(Ir1D zGp)ZsNiy{mS}Au5;(fYf93rs^xvi(H;|H8ECYdC`CiC&G`zw?@)#DjMc7j~daL_A$ z7e3nF2$TKlTi=mOftyFBt8*Xju-OY@2k@f3YBM)-v8+5_o}M?7pxlNn)C0Mcd@87?+AA4{Ti2ptnYYKGp`^FhcJLlT%RwP4k$ad!ho}-^vW;s{6hnjD0*c39k zrm@PkI8_p}mnT&5I@=O1^m?g}PN^8O8rB`;t`6H+?Su0IR?;8txBqwK1Au8O3BZAX zNdJB{bpQWR@J|e=Z>XSXV1DB{uhr3pGf_tb)(cAkp)fS7*Qv))&Vkbb+cvG!j}ukd zxt*C8&RN}5ck{jkw0=Q7ldUp0FQ&Pb_$M7a@^nf`8F%$ftu^jEz36d#^M8Ia{VaTy z5(h$I)*l3i!VpPMW+XGgzL~fcN?{~1QWu9!Gu0jOWWE zNW%&&by0DbXL&^)r-A*7R@;T$P}@3eOj#gqJ!uvTqBL5bupU91UK#d|IdxBUZAeh1 z>rAI#*Y4jv>uhOh7`S@mnsl0g@1C;k$Z%!d*n8#_$)l}-1&z2kr@M+xWoKR z!KySy-7h&Bf}02%JeXmQGjO3ntu={K$jy$rFwfSV8!zqAL_*&e2|CJ06`4&0+ceI026REfNT>JzAdwmIlKLEr2? zaZ#d*XFUN*gpzOxq)cysr&#6zNdDDPH% zd8_>3B}uA7;bP4fKVdd~Og@}dW#74ceETOE- zlZgQqQfEc?-5ly(Z5`L_CCM!&Uxk5#wgo=OLs-kFHFG*cTZ)$VE?c_gQUW&*!2@W2 z7Lq&_Kf88OCo?BHCtwe*&fu&8PQ(R5&lnYo8%+U73U)Ec2&|A)Y~m7(^bh299REPe zn#gyaJ4%o4>diN3z%P5&_aFUmlKytY$t21WGwx;3?UC}vlxi-vdEQgsKQ;=#sJ#ll zZeytjOad$kyON4XxC}frS|Ybh`Yq!<(IrlOXP3*q86ImyV*mJyBn$m~?#xp;EplcM z+6sez%+K}Xj3$YN6{}VL;BZ7Fi|iJj-ywlR+AP8lq~mnt5p_%VmN{Sq$L^z!otu_u znVCl@FgcVXo510e@5(wnko%Pv+^r^)GRh;>#Z(|#cLnu_Y$#_xG&nvuT+~gzJsoSi zBvX`|IS~xaold!`P!h(v|=>!5gk)Q+!0R1Ge7!WpRP{*Ajz$oGG$_?Ajvz6F0X?809o`L8prsJ*+LjlGfSziO;+ zv>fyRBVx#oC0jGK8$%$>Z;0+dfn8x;kHFQ?Rpi7(Rc{Uq{63Kgs{IwLV>pDK7yX-2 zls;?`h!I9YQVVbAj7Ok1%Y+F?CJa-Jl>1x#UVL(lpzBBH4(6v0^4 z3Tf`INjml5`F_kZc5M#^J|f%7Hgxg3#o}Zwx%4l9yYG!WaYUA>+dqpRE3nw#YXIX%= ziH3iYO~jr0nP5xp*VIa#-aa;H&%>{mfAPPlh5Fc!N7^{!z$;p-p38aW{gGx z)dFS62;V;%%fKp&i@+5x=Cn7Q>H`NofJGXmNeh{sOL+Nk>bQJJBw3K*H_$}%*xJM=Kh;s#$@RBR z|75|g85da@#qT=pD777m$wI!Q8SC4Yw3(PVU53bzzGq$IdGQoFb-c_(iA_~qD|eAy z@J+2!tc{|!8fF;%6rY9`Q!Kr>MFwEH%TY0y>Q(D}xGVJM{J{aGN0drG&|1xO!Ttdw z-1^gQ&y~KS5SeslMmoA$Wv$ly={f}f9<{Gm!8ycp*D9m*5Ef{ymIq!MU01*)#J1_! zM_i4{LYButqlQ>Q#o{~W!E_#(S=hR}kIrea_67Z5{W>8PD>g$f;dTvlD=X@T$8D0;BWkle@{VTd&D5^)U>(>g(jFt4lRV6A2(Te->ooI{nk-bZ(gwgh zaH4GT^wXPBq^Gcu%xW#S#p_&x)pNla5%S5;*OG_T^PhIIw1gXP&u5c;{^S(AC*+$> z)GuVq(FT@zq9;i{*9lEsNJZ)??BbSc5vF+Kdh-kL@`(`l5tB4P!9Okin2!-T?}(w% zEpbEU67|lU#@>DppToestmu8Ce=gz=e#V+o)v)#e=N`{$MI5P0O)_fHt1@aIC_QCv=FO`Qf=Ga%^_NhqGI)xtN*^1n{ z&vgl|TrKZ3Vam@wE0p{c3xCCAl+RqFEse@r*a<3}wmJl-hoJoN<|O2zcvMRl<#BtZ z#}-bPCv&OTw`GMp&n4tutf|er`@#d~7X+);##YFSJ)BitGALu}-N*DJdCzs(cQ?I- z6u(WAKH^NUCcOtpt5QTsQRJ$}jN28ZsYx+4CrJUQ%egH zo#tMoywhR*oeIkS%}%WUAIbM`D)R6Ya&@sZvvUEM7`fR0Ga03*=qaEGq4G7-+30Ck zRkje{6A{`ebq?2BTFFYnMM$xcQbz0nEGe!s%}O)m={`075R0N9KTZ>vbv2^eml>@}722%!r#6Wto}?vNst? zs`IasBtcROZG9+%rYaZe^=5y3chDzBf>;|5sP0!sP(t^= z^~go8msT@|rp8LJ8km?4l?Hb%o10h7(ixqV65~5Y>n_zG3AMqM3UxUNj6K-FUgMT7 z*Dy2Y8Ws+%`Z*~m9P zCWQ8L^kA2$rf-S@qHow$J86t)hoU#XZ2YK~9GXVR|*`f6`0&8j|ss_Ai-x=_;Df^*&=bW$1nc{Gplm zF}VF`w)`5A;W@KM`@<9Bw_7~?_@b{Z`n_A6c1AG#h#>Z$K>gX6reEZ*bZRjCup|0# zQ{XAb`n^}2cIwLTN%5Ix`PB*H^(|5S{j?BwItu+MS`1)VW=TnUtt6{3J!WR`4b`LW z?AD#ZmoyYpL=903q3LSM=&5eNP^dwTDRD~iP=}FXgZ@2WqfdyPYl$9do?wX{RU*$S zgQ{OqXK-Yuf4+}x6P#A*la&^G2c2TC;aNNZEYuB(f25|5eYi|rd$;i0qk7^3Ri8of ziP~PVT_|4$n!~F-B1_Et<0OJZ*e+MN;5FFH`iec(lHR+O%O%_RQhvbk-NBQ+$)w{D+dlA0jxI;z|P zEKW`!X)${xzi}Ww5G&@g0akBb_F`ziv$u^hs0W&FXuz=Ap>SUMw9=M?X$`lgPRq11 zqq+n44qL;pgGO+*DEc+Euv*j(#%;>p)yqdl`dT+Og zZH?FXXt`<0XL2@PWYp|7DWzFqxLK)yDXae&3P*#+f+E{I&h=$UPj;ey9b`H?qe*Oj zV|-qgI~v%&oh7rzICXfZmg$8$B|zkjliQ=e4jFgYCLR%yi!9gc7>N z&5G#KG&Hr+UEfB;M(M>$Eh}P$)<_IqC_WKOhO4(cY@Gn4XF(#aENkp&D{sMQgrhDT zXClOHrr9|POHqlmm+*L6CK=OENXbZ+kb}t>oRHE2xVW<;VKR@ykYq04LM9L-b;eo& zl!QQo!Sw{_$-qosixZJWhciN>Gbe8|vEVV2l)`#5vKyrXc6E`zmH(76nGRdL)pqLb@j<&&b!qJRLf>d`rdz}^ZSm7E;+XUJ ziy;xY&>LM?MA^v0Fu8{7hvh_ynOls6CI;kQkS2g^OZr70A}PU;i^~b_hUYN1*j-DD zn$lHQG9(lh&sDii)ip*{;Sb_-Anluh`=l~qhqbI+;=ZzpFrRp&T+UICO!OoqX@Xr_ z32iJ`xSpx=lDDB_IG}k+GTYG@K8{rhTS)aoN8D~Xfe?ul&;jv^E;w$nhu-ICs&Q)% zZ=~kPNZP0-A$pB8)!`TEqE`tY3Mx^`%O`?EDiWsZpoP`e-iQ#E>fIyUx8XN0L z@S-NQwc;0HjSZKWDL}Au_Zkbh!juuB&mGL0=nO5)tUd_4scpPy&O7SNS^aRxUy0^< zX}j*jPrLP4Pa0|PL+nrbd4G;YCxCK-=G7TG?dby~``AIHwxqFu^OJhyIUJkO0O<>_ zcpvg5Fk$Wpj}YE3;GxRK67P_Z@1V#+pu>pRj0!mFf(m_WR3w3*oQy$s39~U7Cb}p(N&8SEwt+)@%o-kW9Ck=^?tvC2$b9% ze9(Jn+H`;uAJE|;$Flha?!*lJ0@lKfZM>B|c)3lIAHb;5OEOT(2453m!LgH2AX=jK zQ93An1-#l@I@mwB#pLc;M7=u6V5IgLl>E%gvE|}Hvd4-bE1>gs(P^C}gTv*&t>W#+ zASLRX$y^DD3Jrht zwyt`yuA1j(TcP*0p*Xkv>gh+YTLrcN_HuaRMso~0AJg`^nL#52dGBzY+_7i)Ud#X) zVwg;6$WV20U2uyKt8<)jN#^1>PLg`I`@Mmut*Zy!c!zshSA!e^tWVoKJD%jN&ml#{ z@}B$j=U5J_#rc%T7(DGKF+WwIblEZ;Vq;CsG~OKxhWYGJx#g7fxb-_ya*D0=_Ys#f zhXktl=Vnw#Z_neW>Xe#EXT(4sT^3p6srKby4Ma5LLfh6XrHGFGgM;5Z}jv-T!f~=jT&n>Rk z4U0RT-#2fsYCQhwtW&wNp6T(im4dq>363H^ivz#>Sj;TEKY<)dOQU=g=XsLZhnR>e zd}@p1B;hMsL~QH2Wq>9Zb; zK`0`09fzuYg9MLJe~cdMS6oxoAD{kW3sFAqDxvFM#{GpP^NU@9$d5;w^WgLYknCTN z0)N425mjsJTI@#2kG-kB!({*+S(WZ-{SckG5^OiyP%(6DpRsx60$H8M$V65a_>oME z^T~>oG7r!ew>Y)&^MOBrgc-3PezgTZ2xIhXv%ExMFgSf5dQbD=Kj*!J4k^Xx!Z>AW ziZfvqJvtm|EXYsD%A|;>m1Md}j5f2>kt*gngL=enh<>#5iud0dS1P%u2o+>VQ{U%(nQ_WTySY(s#~~> zrTsvp{lTSup_7*Xq@qgjY@1#bisPCRMMHnOL48qi*jQ0xg~TSW%KMG9zN1(tjXix()2$N}}K$AJ@GUth+AyIhH6Aeh7qDgt#t*`iF5#A&g4+ zWr0$h9Zx6&Uo2!Ztcok($F>4NA<`dS&Js%L+67FT@WmI)z#fF~S75TUut%V($oUHw z$IJsL0X$KfGPZYjB9jaj-LaoDD$OMY4QxuQ&vOGo?-*9@O!Nj>QBSA6n$Lx|^ zky)4+sy{#6)FRqRt6nM9j2Lzba!U;aL%ZcG&ki1=3gFx6(&A3J-oo|S2_`*w9zT)W z4MBOVCp}?4nY)1))SOX#6Zu0fQQ7V{RJq{H)S#;sElY)S)lXTVyUXTepu4N)n85Xo zIpWPT&rgnw$D2Fsut#Xf-hO&6uA0n~a;a3!=_!Tq^TdGE&<*c?1b|PovU}3tfiIUu z){4W|@PY}zJOXkGviCw^x27%K_Fm9GuKVpd{P2>NJlnk^I|h2XW0IO~LTMj>2<;S* zZh2uRNSdJM$U$@=`zz}%;ucRx{aKVxxF7?0hdKh6&GxO6f`l2kFncS3xu0Ly{ew0& zeEP*#lk-8-B$LD(5yj>YFJ{yf5zb41PlW7S{D9zC4Aa4nVdkDNH{UsFJp)q-`9OYt zbOKkigbmm5hF?tttn;S4g^142AF^`kiLUC?e7=*JH%Qe>uW=dB24NQa`;lm5yL>Dyh@HbHy-f%6Vz^ zh&MgwYsh(z#_fhhqY$3*f>Ha}*^cU-r4uTHaT?)~LUj5``FcS46oyoI5F3ZRizVD% zPFY(_S&5GN8$Nl2=+YO6j4d|M6O7CmUyS&}m4LSn6}J`$M0ZzT&Ome)ZbJDFvM&}A zZdhDn(*viM-JHf84$!I(8eakl#zRjJH4qfw8=60 z11Ely^FyXjVvtv48-Fae7p=adlt9_F^j5#ZDf7)n!#j?{W?@j$Pi=k`>Ii>XxrJ?$ z^bhh|X6qC8d{NS4rX5P!%jXy=>(P+r9?W(2)|(=a^s^l~x*^$Enw$~u%WRuRHHFan{X|S;FD(Mr z@r@h^@Bs#C3G;~IJMrERd+D!o?HmFX&#i|~q(7QR3f8QDip?ms6|GV_$86aDb|5pc?_-jo6vmWqYi{P#?{m_AesA4xX zi&ki&lh0yvf*Yw~@jt|r-=zpj!bw<6zI3Aa^Wq{|*WEC}I=O!Re!l~&8|Vu<$yZ1p zs-SlwJD8K!$(WWyhZ+sOqa8cciwvyh%zd`r$u;;fsHn!hub0VU)bUv^QH?x30#;tH zTc_VbZj|prj7)d%ORU;Vs{#ERb>K8>GOLSImnF7JhR|g$7FQTU{(a7RHQ*ii-{U3X z^7+vM0R$8b3k1aSU&kxvVPfOz3~)0O2iTYinV9_5{pF18j4b{o`=@AZIOAwwedB2@ ztXI1F04mg{<>a-gdFoRjq$6#FaevDn$^06L)k%wYq03&ysdXE+LL1#w$rRS1Y;BoS zH1x}{ms>LHWmdtP(ydD!aRdAa(d@csEo z0EF9L>%tppp`CZ2)jVb8AuoYyu;d^wfje6^n6`A?6$&%$p>HcE_De-Zh)%3o5)LDa zskQ}%o7?bg$xUj|n8gN9YB)z!N&-K&!_hVQ?#SFj+MpQA4@4oq!UQ$Vm3B`W_Pq3J z=ngFP4h_y=`Iar<`EESF9){%YZVyJqLPGq07TP7&fSDmnYs2NZQKiR%>){imTBJth zPHr@p>8b+N@~%43rSeNuOz;rgEm?14hNtI|KC6Xz1d?|2J`QS#`OW7gTF_;TPPxu@ z)9J9>3Lx*bc>Ielg|F3cou$O0+<b34_*ZJhpS&$8DP>s%47a)4ZLw`|>s=P_J4u z?I_%AvR_z8of@UYWJV?~c4Yb|A!9n!LEUE6{sn@9+D=0w_-`szJ_T++x3MN$v-)0d zy`?1QG}C^KiNlnJBRZBLr4G~15V3$QqC%1G5b#CEB0VTr#z?Ug%Jyv@a`QqAYUV~^ zw)d|%0g&kl{j#FMdf$cn(~L@8s~6eQ)6{`ik(RI(o9s0g30Li{4YoxcVoYd+LpeLz zai?~r)UcbYr@lv*Z>E%BsvTNd`Sc?}*}>mzJ|cr0Y(6rA7H_6&t>F{{mJ^xovc2a@ zFGGDUcGgI-z6H#o@Gj29C=Uy{wv zQHY2`HZu8+sBQK*_~I-_>fOTKEAQ8_Q~YE$c?cSCxI;vs-JGO`RS464Ft06rpjn+a zqRS0Y3oN(9HCP@{J4mOWqIyD8PirA!pgU^Ne{LHBG;S*bZpx3|JyQDGO&(;Im8!ed zNdpE&?3U?E@O~>`@B;oY>#?gXEDl3pE@J30R1;?QNNxZ?YePc)3=NS>!STCrXu*lM z69WkLB_RBwb1^-zEm*tkcHz3H;?v z;q+x0Jg$|?5;e1-kbJnuT+^$bWnYc~1qnyVTKh*cvM+8yJT-HBs1X@cD;L$su65;i z2c1MxyL~NuZ9+)hF=^-#;dS#lFy^Idcb>AEDXu1!G4Kd8YPy~0lZz$2gbv?su}Zn} zGtIbeYz3X8OA9{sT(aleold_?UEV{hWRl(@)NH6GFH@$<8hUt=dNte%e#Jc>7u9xi zuqv!CRE@!fmZZ}3&@$D>p0z=*dfQ_=IE4bG0hLmT@OP>x$e`qaqf_=#baJ8XPtOpWi%$ep1Y)o2(sR=v)M zt(z*pGS$Z#j_xq_lnCr+x9fwiT?h{NEn#iK(o)G&Xw-#DK?=Ms6T;%&EE${Gq_%99 z6(;P~jPKq9llc+cmI(MKQ6*7PcL)BmoI}MYFO)b3-{j>9FhNdXLR<^mnMP`I7z0v` zj3wxcXAqi4Z0kpeSf>?V_+D}NULgU$DBvZ^=0G8Bypd7P2>;u`yW9`%4~&tzNJpgp zqB+iLIM~IkB;ts!)exn643mAJ8-WlgFE%Rpq!UMYtB?$5QAMm)%PT0$$2{>Yu7&U@ zh}gD^Qdgu){y3ANdB5{75P;lRxSJPSpQPMJOiwmpMdT|?=q;&$aTt|dl~kvS z+*i;6cEQJ1V`R4Fd>-Uzsc=DPQ7A7#VPCIf!R!KK%LM&G%MoZ0{-8&99H!|UW$Ejv zhDLX3ESS6CgWTm#1ZeS2HJb`=UM^gsQ84dQpX(ESWSkjn>O zVxg%`@mh(X9&&wN$lDIc*@>rf?C0AD_mge3f2KkT6kGySOhXqZjtA?5z`vKl_{(5g z&%Y~9p?_DL{+q@siT~*3Q*$nWXQfNN;%s_eHP_A;O`N`SaoB z6xYR;z_;HQ2xAa9xKgx~2f2xEKiEDpGPH1d@||v#f#_Ty6_gY>^oZ#xac?pc-F`@ z*}8sPV@xiz?efDMcmmezYVw~qw=vT;G1xh+xRVBkmN66!u(mRG3G6P#v|;w@anEh7 zCf94arw%YB*=&3=RTqX?z4mID$W*^+&d6qI*LA-yGme;F9+wTsNXNaX~zl2+qIK&D-aeN4lr0+yP;W>|Dh?ms_ogT{DT+ ztXFy*R7j4IX;w@@R9Oct5k2M%&j=c_rWvoul+` z<18FH5D@i$P38W9VU2(EnEvlJ(SHCqTNBa)brkIjGP|jCnK&Qi%97tikU}Y#3L?s! z2ujL%YiHO-#!|g5066V01hgT#>fzls7P>+%D~ogOT&!Whb4iF=CnCto82Yb#b`YoVsj zS2q^W0Rj!RrM@=_GuPQy5*_X@Zmu`TKSbqEOP@;Ga&Rrr>#H@L41@ZX)LAkbo{G8+ z;!5EH6vv-ip0`tLB)xUuOX(*YEDSWf?PIxXe`+_B8=KH#HFCfthu}QJylPMTNmoV; zC63g%?57(&osaH^sxCyI-+gwVB|Xs2TOf=mgUAq?V~N_5!4A=b{AXbDae+yABuuu3B_XSa4~c z1s-OW>!cIkjwJf4ZhvT|*IKaRTU)WAK=G|H#B5#NB9<{*kt?7`+G*-^<)7$Iup@Um z7u*ABkG3F*Foj)W9-I&@BrN8(#$7Hdi`BU#SR1Uz4rh&=Ey!b76Qo?RqBJ!U+rh(1 znw@xw5$)4D8OWtB_^pJO*d~2Mb-f~>I!U#*=Eh*xa6$LX?4Evp4%;ENQR!mF4`f7F zpG!NX=qnCwE8@NAbQV`*?!v0;NJ(| zBip8}VgFVsXFqslXUV>_Z>1gmD(7p#=WACXaB|Y`=Kxa=p@_ALsL&yAJ`*QW^`2@% zW7~Yp(Q@ihmkf{vMF?kqkY%SwG^t&CtfRWZ{syK@W$#DzegcQ1>~r7foTw3^V1)f2Tq_5f$igmfch;8 zT-<)?RKcCdQh6x^mMEOS;4IpQ@F2q-4IC4%*dU@jfHR4UdG>Usw4;7ESpORL|2^#jd+@zxz{(|RV*1WKrw-)ln*8LnxVkKDfGDHA%7`HaiuvhMu%*mY9*Ya{Ti#{DW?i0 zXXsp+Bb(_~wv(3t70QU3a$*<$1&zm1t++x#wDLCRI4K)kU?Vm9n2c0m@TyUV&&l9%}fulj!Z9)&@yIcQ3gX}l0b1LbIh4S z5C*IDrYxR%qm4LVzSk{0;*npO_SocYWbkAjA6(^IAwUnoAzw_Uo}xYFo?Y<-4Zqec z&k7HtVlFGyt_pA&kX%P8PaRD8y!Wsnv}NMLNLy-CHZf(ObmzV|t-iC#@Z9*d-zUsx zxcYWw{H)nYXVdnJu5o-U+fn~W z-$h1ax>h{NlWLA7;;6TcQHA>UJB$KNk74T1xNWh9)kwK~wX0m|Jo_Z;g;>^E4-k4R zRj#pQb-Hg&dAh}*=2;JY*aiNZzT=IU&v|lQY%Q|=^V5pvTR7^t9+@+ST&sr!J1Y9a z514dYZn5rg6@4Cy6P`-?!3Y& z?B*5zw!mTiD2)>f@3XYrW^9V-@%YFkE_;PCyCJ7*?_3cR%tHng9%ZpIU}LJM=a+0s z(SDDLvcVa~b9O!cVL8)Q{d^R^(bbG=Ia$)dVN_tGMee3PMssZ7Z;c^Vg_1CjZYTnq z)wnF8?=-MmqVOMX!iE?YDvHCN?%TQtKJMFHp$~kX4}jZ;EDqP$?jqJZjoa2PM@$uZ zF4}iab1b5ep)L;jdegC3{K4VnCH#OV;pRcSa(&Nm50ze-yZ8*cGv;@+N+A?ncc^2z9~|(xFhwOHmPW@ zR5&)E^YKQj@`g=;zJ_+CLamsPuvppUr$G1#9urUj+p-mPW_QSSHkPMS!52t>Hqy|g z_@Yu3z%|wE=uYq8G>4`Q!4zivS}+}{m5Zjr7kMRGn_p&hNf|pc&f9iQ`^%78rl#~8 z;os@rpMA{ZioY~(Rm!Wf#Wx##A0PthOI341QiJ=G*#}pDAkDm+{0kz&*NB?rC0-)glB{0_Tq*^o zVS1>3REsv*Qb;qg!G^9;VoK)P*?f<*H&4Su1=}bP^Y<2PwFpoqw#up4IgX3L z`w~8jsFCI3k~Y9g(Y9Km`y$0FS5vHb)kb)Jb6q-9MbO{Hbb zxg?IWQ1ZIGgE}wKm{axO6CCh~4DyoFU+i1xn#oyfe+<{>=^B5tm!!*1M?AW8c=6g+%2Ft97_Hq&ZmOGvqGQ!Bn<_Vw`0DRuDoB6q8ME<;oL4kocr8E$NGoLI zXWmI7Af-DR|KJw!vKp2SI4W*x%A%5BgDu%8%Iato+pWo5`vH@!XqC!yK}KLzvfS(q z{!y(S-PKbk!qHsgVyxKsQWk_8HUSSmslUA9nWOjkKn0%cwn%yxnkfxn?Y2rysXKS=t-TeI%DN$sQ{lcD!(s>(4y#CSxZ4R} zFDI^HPC_l?uh_)-^ppeYRkPTPu~V^0Mt}#jrTL1Q(M;qVt4zb(L|J~sxx7Lva9`mh zz!#A9tA*6?q)xThc7(gB2Ryam$YG4qlh00c}r&$y6u zIN#Qxn{7RKJ+_r|1G1KEv!&uKfXpOVZ8tK{M775ws%nDyoZ?bi3NufNbZs)zqXiqc zqOsK@^OnlFMAT&mO3`@3nZP$3lLF;ds|;Z{W(Q-STa2>;)tjhR17OD|G>Q#zJHb*> zMO<{WIgB%_4MG0SQi2;%f0J8l_FH)Lfaa>*GLobD#AeMttYh4Yfg22@q4|Itq};NB z8;o*+@APqy@fPgrc&PTbGEwdEK=(x5K!If@R$NiO^7{#j9{~w=RBG)ZkbOw@$7Nhl zyp{*&QoVBd5lo{iwl2gfyip@}IirZK;ia(&ozNl!-EEYc=QpYH_= zJkv7gA{!n4up6$CrzDJIBAdC7D5D<_VLH*;OYN>_Dx3AT`K4Wyx8Tm{I+xplKP6k7 z2sb!i7)~%R#J0$|hK?~=u~rnH7HCUpsQJujDDE*GD`qrWWog+C+E~GGy|Hp_t4--} zrxtrgnPh}r=9o}P6jpAQuDN}I*GI`8&%Lp-C0IOJt#op)}XSr!ova@w{jG2V=?GXl3zEJJFXg)U3N>BQP z*Lb@%Mx|Tu;|u>$-K(q^-HG!EQ3o93%w(A7@ngGU)HRWoO&&^}U$5x+T&#zri>6ct zXOB#EF-;z3j311K`jrYyv6pOPF=*`SOz!ack=DuEi({UnAkL5H)@R?YbRKAeP|06U z?-Ns0ZxD0h9D8)P66Sq$w-yF+1hEVTaul%&=kKDrQtF<$RnQPZ)ezm1`aHIjAY=!S z`%vboP`?7mItgEo4w50C*}Ycqp9_3ZEr^F1;cEhkb`BNhbc6PvnXu@wi=AoezF4~K zkxx%ps<8zb=wJ+9I8o#do)&{(=yAlNdduaDn!=xGSiuo~fLw~Edw$6;l-qaq#Z7?# zGrdU(Cf-V@$x>O%yRc6!C1Vf`b19ly;=mEu8u9|zitcG^O`lbNh}k=$%a)UHhDwTEKis2yc4rBGR>l*(B$AC7ung&ssaZGkY-h(fpwcPyJSx*9EIJMRKbMP9}$nVrh6$g-Q^5Cw)BeWqb-qi#37ZXKL!GR;ql)~ z@PP*-oP?T|ThqlGKR84zi^CN z4TZ1A)7vL>ivoL2EU_~xl-P{p+sE}9CRwGJDKy{>0KP+gj`H9C+4fUMPnIB1_D`A- z$1`G}g0lQmqMN{Y&8R*$xYUB*V}dQPxGVZQ+rH!DVohIoTbh%#z#Tru%Px@C<=|og zGDDwGq7yz`%^?r~6t&>x*^We^tZ4!E4dhwsht#Pb1kCY{q#Kv;z%Dp#Dq;$vH$-(9 z8S5tutZ}&JM2Iw&Y-7KY4h5BBvS=Ove0#+H2qPdR)WyI zYcj)vB=MA{7T|3Ij_PN@FM@w(C9ANBq&|NoW30ccr~i#)EcH)T^3St~rJ0HKKd4wr z@_+132;Bj+>UC@h)Ap*8B4r5A1lZ!Dh%H7&&hBnlFj@eayk=VD*i5AQc z$uN8YG#PL;cuQa)Hyt-}R?&NAE1QT>svJDKt*)AQOZAJ@ zyxJoBebiobHeFlcLwu_iI&NEZuipnOR;Tn;PbT1Mt-#5v5b*8ULo7m)L-eti=UcGf zRZXidmxeFgY!y80-*PH-*=(-W+fK%KyUKpg$X@tuv``tXj^*4qq@UkW$ZrAo%+hay zU@a?z&2_@y)o@D!_g>NVxFBO!EyB&6Z!nd4=KyDP^hl!*(k{dEF6@NkXztO7gIh zQ&PC+p-8WBv;N(rpfKdF^@Z~|E6pa)M1NBUrCZvLRW$%N%xIbv^uv?=C!=dDVq3%* zgvbEBnG*JB*@vXx8>)7XL*!{1Jh=#2UrByF7U?Rj_}VYw88BwqefT_cCTv8aTrRVjnn z1HNCF=44?*&gs2`vCGJVHX@kO z240eo#z+FhI0=yy6NHQwZs}a+J~4U-6X`@ zZ7j+tb##m`x%J66$a9qXDHG&^kp|GkFFMmjD(Y-k_ClY~N$H|n@NkSDz=gg?*2ga5 z)+f)MEY>2Lp15;~o`t`qj;S>BaE;%dv@Ux11yq}I(k|o&`5UZFUHn}1kE^gIK@qV& z!S2IhyU;->VfA4Qb}m7YnkIa9%z{l~iPWo2YPk-`hy2-Eg=6E$21plQA5W2qMZDFU z-a-@Dndf%#on6chT`dOKnU9}BJo|kJwgGC<^nfo34zOKH96LbWY7@Wc%EoFF=}`VU zksP@wd%@W;-p!e^&-)N7#oR331Q)@9cx=mOoU?_Kih2!Le*8fhsZ8Qvo6t2vt+UOZ zw|mCB*t2%z21YqL>whu!j?s~}-L`OS+jdg1(XnmYw$rg~r(?5Y+qTg`$F}q3J?GtL z@BN&8#`u2RqkdG4yGGTus@7U_%{6C{XAhFE!2SelH?KtMtX@B1GBhEIDL-Bj#~{4! zd}p7!#XE9Lt;sy@p5#Wj*jf8zGv6tTotCR2X$EVOOup;GnRPRVU5A6N@Lh8?eA7k? zn~hz&gY;B0ybSpF?qwQ|sv_yO=8}zeg2$0n3A8KpE@q26)?707pPw?H76lCpjp=5r z6jjp|auXJDnW}uLb6d7rsxekbET9(=zdTqC8(F5@NNqII2+~yB;X5iJNQSiv`#ozm zf&p!;>8xAlwoxUC3DQ#!31ylK%VrcwS<$WeCY4V63V!|221oj+5#r}fGFQ}|uwC0) zNl8(CF}PD`&Sj+p{d!B&&JtC+VuH z#>US`)YQrhb6lIAYb08H22y(?)&L8MIQsA{26X`R5Km{YU)s!x(&gIsjDvq63@X`{ z=7{SiH*_ZsPME#t2m|bS76Uz*z{cpp1m|s}HIX}Ntx#v7Eo!1%G9__4dGSGl`p+xi zZ!VK#Qe;Re=9bqXuW+0DSP{uZ5-QXrNn-7qW19K0qU}OhVru7}3vqsG?#D67 zb}crN;QwsH*vymw(maZr_o|w&@sQki(X+D)gc5Bt&@iXisFG;eH@5d43~Wxq|HO(@ zV-rip4n#PEkHCWCa5d?@cQp^B;I-PzOfag|t-cuvTapQ@MWLmh*41NH`<+A+JGyKX zyYL6Ba7qqa5j@3lOk~`OMO7f0!@FaOeZxkbG@vXP(t3#U*fq8=GAPqUAS>vW2uxMk{a(<0=IxB;# zMW;M+owrHaZBp`3{e@7gJCHP!I(EeyGFF;pdFPdeP+KphrulPSVidmg#!@W`GpD&d z9p6R`dpjaR2E1Eg)Ws{BVCBU9-aCgN57N~uLvQZH`@T+2eOBD%73rr&sV~m#2~IZx zY_8f8O;XLu2~E3JDXnGhFvsyb^>*!D>5EtlKPe%kOLv6*@=Jpci`8h0z?+fbBUg_7 zu6DjqO=$SjAv{|Om5)nz41ZkS4E_|fk%NDY509VV5yNeo%O|sb>7C#wj8mL9cEOFh z>nDz%?vb!h*!0dHdnxDA>97~EoT~!N40>+)G2CeYdOvJr5^VnkGz)et&T9hrD(VAgCAJjQ7V$O?csICB*HFd^k@$M5*v$PZJD-OVL?Ze(U=XGqZPVG8JQ z<~ukO%&%nNXYaaRibq#B1KfW4+XMliC*Tng2G(T1VvP;2K~;b$EAqthc${gjn_P!b zs62UT(->A>!ot}cJXMZHuy)^qfqW~xO-In2);e>Ta{LD6VG2u&UT&a@>r-;4<)cJ9 zjpQThb4^CY)Ev0KR7TBuT#-v}W?Xzj{c7$S5_zJA57Qf=$4^npEjl9clH0=jWO8sX z3Fuu0@S!WY>0XX7arjH`?)I<%2|8HfL!~#c+&!ZVmhbh`wbzy0Ux|Jpy9A{_7GGB0 zadZ48dW0oUwUAHl%|E-Q{gA{z6TXsvU#Hj09<7i)d}wa+Iya)S$CVwG{4LqtB>w%S zKZx(QbV7J9pYt`W4+0~f{hoo5ZG<0O&&5L57oF%hc0xGJ@Zrg_D&lNO=-I^0y#3mxCSZFxN2-tN_mU@7<@PnWG?L5OSqkm8TR!`| zRcTeWH~0z1JY^%!N<(TtxSP5^G9*Vw1wub`tC-F`=U)&sJVfvmh#Pi`*44kSdG};1 zJbHOmy4Ot|%_?@$N?RA9fF?|CywR8Sf(SCN_luM8>(u0NSEbKUy7C(Sk&OuWffj)f za`+mo+kM_8OLuCUiA*CNE|?jra$M=$F3t+h-)?pXz&r^F!ck;r##`)i)t?AWq-9A9 zSY{m~TC1w>HdEaiR*%j)L);H{IULw)uxDO>#+WcBUe^HU)~L|9#0D<*Ld459xTyew zbh5vCg$a>`RCVk)#~ByCv@Ce!nm<#EW|9j><#jQ8JfTmK#~jJ&o0Fs9jz0Ux{svdM4__<1 zrb>H(qBO;v(pXPf5_?XDq!*3KW^4>(XTo=6O2MJdM^N4IIcYn1sZZpnmMAEdt}4SU zPO54j2d|(xJtQ9EX-YrlXU1}6*h{zjn`in-N!Ls}IJsG@X&lfycsoCemt_Ym(PXhv zc*QTnkNIV=Ia%tg%pwJtT^+`v8ng>;2~ps~wdqZSNI7+}-3r+#r6p`8*G;~bVFzg= z!S3&y)#iNSUF6z;%o)%h!ORhE?CUs%g(k2a-d576uOP2@QwG-6LT*G!I$JQLpd`cz z-2=Brr_+z96a0*aIhY2%0(Sz=|D`_v_7h%Yqbw2)8@1DwH4s*A82krEk{ zoa`LbCdS)R?egRWNeHV8KJG0Ypy!#}kslun?67}^+J&02!D??lN~t@;h?GS8#WX`)6yC**~5YNhN_Hj}YG<%2ao^bpD8RpgV|V|GQwlL27B zEuah|)%m1s8C6>FLY0DFe9Ob66fo&b8%iUN=y_Qj;t3WGlNqP9^d#75ftCPA*R4E8 z)SWKBKkEzTr4JqRMEs`)0;x8C35yRAV++n(Cm5++?WB@ya=l8pFL`N0ag`lWhrYo3 zJJ$< zQ*_YAqIGR*;`VzAEx1Pd4b3_oWtdcs7LU2#1#Ls>Ynvd8k^M{Ef?8`RxA3!Th-?ui{_WJvhzY4FiPxA?E4+NFmaC-Uh*a zeLKkkECqy>Qx&1xxEhh8SzMML=8VP}?b*sgT9ypBLF)Zh#w&JzP>ymrM?nnvt!@$2 zh>N$Q>mbPAC2kNd&ab;FkBJ}39s*TYY0=@e?N7GX>wqaM>P=Y12lciUmve_jMF0lY zBfI3U2{33vWo(DiSOc}!5##TDr|dgX1Uojq9!vW3$m#zM_83EGsP6&O`@v-PDdO3P z>#!BEbqpOXd5s?QNnN!p+92SHy{sdpePXHL{d@c6UilT<#~I!tH$S(~o}c#(j<2%! zQvm}MvAj-95Ekx3D4+|e%!?lO(F+DFw9bxb-}rsWQl)b44###eUg4N?N-P(sFH2hF z`{zu?LmAxn2=2wCE8?;%ZDi#Y;Fzp+RnY8fWlzVz_*PDO6?Je&aEmuS>=uCXgdP6r zoc_JB^TA~rU5*geh{G*gl%_HnISMS~^@{@KVC;(aL^ZA-De+1zwUSXgT>OY)W?d6~ z72znET0m`53q%AVUcGraYxIcAB?OZA8AT!uK8jU+=t;WneL~|IeQ>$*dWa#x%rB(+ z5?xEkZ&b{HsZ4Ju9TQ|)c_SIp`7r2qMJgaglfSBHhl)QO1aNtkGr0LUn{@mvAt=}nd7#>7ru}&I)FNsa*x?Oe3-4G`HcaR zJ}c%iKlwh`x)yX1vBB;-Nr=7>$~(u=AuPX2#&Eh~IeFw%afU+U)td0KC!pHd zyn+X$L|(H3uNit-bpn7%G%{&LsAaEfEsD?yM<;U2}WtD4KuVKuX=ec9X zIe*ibp1?$gPL7<0uj*vmj2lWKe`U(f9E{KVbr&q*RsO;O>K{i-7W)8KG5~~uS++56 zm@XGrX@x+lGEjDQJp~XCkEyJG5Y57omJhGN{^2z5lj-()PVR&wWnDk2M?n_TYR(gM zw4kQ|+i}3z6YZq8gVUN}KiYre^sL{ynS}o{z$s&I z{(rWaLXxcQ=MB(Cz7W$??Tn*$1y(7XX)tv;I-{7F$fPB%6YC7>-Dk#=Y8o1=&|>t5 zV_VVts>Eb@)&4%m}!K*WfLoLl|3FW)V~E1Z!yu`Sn+bAP5sRDyu7NEbLt?khAyz-ZyL-}MYb&nQ zU16f@q7E1rh!)d%f^tTHE3cVoa%Xs%rKFc|temN1sa)aSlT*)*4k?Z>b3NP(IRXfq zlB^#G6BDA1%t9^Nw1BD>lBV(0XW5c?l%vyB3)q*;Z5V~SU;HkN;1kA3Nx!$!9wti= zB8>n`gt;VlBt%5xmDxjfl0>`K$fTU-C6_Z;!A_liu0@Os5reMLNk;jrlVF^FbLETI zW+Z_5m|ozNBn7AaQ<&7zk}(jmEdCsPgmo%^GXo>YYt82n&7I-uQ%A;k{nS~VYGDTn zlr3}HbWQG6xu8+bFu^9%%^PYCbkLf=*J|hr>Sw+#l(Y#ZGKDufa#f-f0k-{-XOb4i zwVG1Oa0L2+&(u$S7TvedS<1m45*>a~5tuOZ;3x%!f``{=2QQlJk|b4>NpD4&L+xI+ z+}S(m3}|8|Vv(KYAGyZK5x*sgwOOJklN0jsq|BomM>OuRDVFf_?cMq%B*iQ*&|vS9 zVH7Kh)SjrCBv+FYAE=$0V&NIW=xP>d-s7@wM*sdfjVx6-Y@=~>rz%2L*rKp|*WXIz z*vR^4tV&7MQpS9%{9b*>E9d_ls|toL7J|;srnW{l-}1gP_Qr-bBHt=}PL@WlE|&KH zCUmDLZb%J$ZzNii-5VeygOM?K8e$EcK=z-hIk63o4y63^_*RdaitO^THC{boKstphXZ2Z+&3ToeLQUG(0Frs?b zCxB+65h7R$+LsbmL51Kc)pz_`YpGEzFEclzb=?FJ=>rJwgcp0QH-UuKRS1*yCHsO) z-8t?Zw|6t($Eh&4K+u$I7HqVJBOOFCRcmMMH};RX_b?;rnk`rz@vxT_&|6V@q0~Uk z9ax|!pA@Lwn8h7syrEtDluZ6G!;@=GL> zse#PRQrdDs=qa_v@{Wv(3YjYD0|qocDC;-F~&{oaTP?@pi$n z1L6SlmFU2~%)M^$@C(^cD!y)-2SeHo3t?u3JiN7UBa7E2 z;<+_A$V084@>&u)*C<4h7jw9joHuSpVsy8GZVT;(>lZ(RAr!;)bwM~o__Gm~exd`K zKEgh2)w?ReH&syI`~;Uo4`x4$&X+dYKI{e`dS~bQuS|p zA`P_{QLV3r$*~lb=9vR^H0AxK9_+dmHX}Y} zIV*#65%jRWem5Z($ji{!6ug$En4O*=^CiG=K zp4S?+xE|6!cn$A%XutqNEgUqYY3fw&N(Z6=@W6*bxdp~i_yz5VcgSj=lf-6X1Nz75 z^DabwZ4*70$$8NsEy@U^W67tcy7^lNbu;|kOLcJ40A%J#pZe0d#n zC{)}+p+?8*ftUlxJE*!%$`h~|KZSaCb=jpK3byAcuHk7wk@?YxkT1!|r({P*KY^`u z!hw#`5$JJZGt@nkBK_nwWA31_Q9UGvv9r-{NU<&7HHMQsq=sn@O?e~fwl20tnSBG* zO%4?Ew6`aX=I5lqmy&OkmtU}bH-+zvJ_CFy z_nw#!8Rap5Wcex#5}Ldtqhr_Z$}@jPuYljTosS1+WG+TxZ>dGeT)?ZP3#3>sf#KOG z0)s%{cEHBkS)019}-1A2kd*it>y65-C zh7J9zogM74?PU)0c0YavY7g~%j%yiWEGDb+;Ew5g5Gq@MpVFFBNOpu0x)>Yn>G6uo zKE%z1EhkG_N5$a8f6SRm(25iH#FMeaJ1^TBcBy<04ID47(1(D)q}g=_6#^V@yI?Y&@HUf z`;ojGDdsvRCoTmasXndENqfWkOw=#cV-9*QClpI03)FWcx(m5(P1DW+2-{Hr-`5M{v##Zu-i-9Cvt;V|n)1pR^y ztp3IXzHjYWqabuPqnCY9^^;adc!a%Z35VN~TzwAxq{NU&Kp35m?fw_^D{wzB}4FVXX5Zk@#={6jRh%wx|!eu@Xp;%x+{2;}!&J4X*_SvtkqE#KDIPPn@ z5BE$3uRlb>N<2A$g_cuRQM1T#5ra9u2x9pQuqF1l2#N{Q!jVJ<>HlLeVW|fN|#vqSnRr<0 zTVs=)7d`=EsJXkZLJgv~9JB&ay16xDG6v(J2eZy;U%a@EbAB-=C?PpA9@}?_Yfb&) zBpsih5m1U9Px<+2$TBJ@7s9HW>W){i&XKLZ_{1Wzh-o!l5_S+f$j^RNYo85}uVhN# zq}_mN-d=n{>fZD2Lx$Twd2)}X2ceasu91}n&BS+4U9=Y{aZCgV5# z?z_Hq-knIbgIpnkGzJz-NW*=p?3l(}y3(aPCW=A({g9CpjJfYuZ%#Tz81Y)al?!S~ z9AS5#&nzm*NF?2tCR#|D-EjBWifFR=da6hW^PHTl&km-WI9*F4o>5J{LBSieVk`KO z2(^9R(zC$@g|i3}`mK-qFZ33PD34jd_qOAFj29687wCUy>;(Hwo%Me&c=~)V$ua)V zsaM(aThQ3{TiM~;gTckp)LFvN?%TlO-;$y+YX4i`SU0hbm<})t0zZ!t1=wY&j#N>q zONEHIB^RW6D5N*cq6^+?T}$3m|L{Fe+L!rxJ=KRjlJS~|z-&CC{#CU8`}2|lo~)<| zk?Wi1;Cr;`?02-C_3^gD{|Ryhw!8i?yx5i0v5?p)9wZxSkwn z3C;pz25KR&7{|rc4H)V~y8%+6lX&KN&=^$Wqu+}}n{Y~K4XpI-#O?L=(2qncYNePX zTsB6_3`7q&e0K67=Kg7G=j#?r!j0S^w7;0?CJbB3_C4_8X*Q%F1%cmB{g%XE&|IA7 z(#?AeG{l)s_orNJp!$Q~qGrj*YnuKlV`nVdg4vkTNS~w$4d^Oc3(dxi(W5jq0e>x} z(GN1?u2%Sy;GA|B%Sk)ukr#v*UJU%(BE9X54!&KL9A^&rR%v zIdYt0&D59ggM}CKWyxGS@ z>T#})2Bk8sZMGJYFJtc>D#k0+Rrrs)2DG;(u(DB_v-sVg=GFMlSCx<&RL;BH}d6AG3VqP!JpC0Gv6f8d|+7YRC@g|=N=C2 zo>^0CE0*RW?W))S(N)}NKA)aSwsR{1*rs$(cZIs?nF9)G*bSr%%SZo^YQ|TSz={jX z4Z+(~v_>RH0(|IZ-_D_h@~p_i%k^XEi+CJVC~B zsPir zA0Jm2yIdo4`&I`hd%$Bv=Rq#-#bh{Mxb_{PN%trcf(#J3S1UKDfC1QjH2E;>wUf5= ze8tY9QSYx0J;$JUR-0ar6fuiQTCQP#P|WEq;Ez|*@d?JHu-(?*tTpGHC+=Q%H>&I> z*jC7%nJIy+HeoURWN%3X47UUusY2h7nckRxh8-)J61Zvn@j-uPA@99|y48pO)0XcW zX^d&kW^p7xsvdX?2QZ8cEUbMZ7`&n{%Bo*xgFr4&fd#tHOEboQos~xm8q&W;fqrj} z%KYnnE%R`=`+?lu-O+J9r@+$%YnqYq!SVs>xp;%Q8p^$wA~oynhnvIFp^)Z2CvcyC zIN-_3EUHW}1^VQ0;Oj>q?mkPx$Wj-i7QoXgQ!HyRh6Gj8p~gH22k&nmEqUR^)9qni{%uNeV{&0-H60C zibHZtbV=8=aX!xFvkO}T@lJ_4&ki$d+0ns3FXb+iP-VAVN`B7f-hO)jyh#4#_$XG%Txk6M<+q6D~ zi*UcgRBOoP$7P6RmaPZ2%MG}CMfs=>*~(b97V4+2qdwvwA@>U3QQAA$hiN9zi%Mq{ z*#fH57zUmi)GEefh7@`Uy7?@@=BL7cXbd{O9)*lJh*v!@ z-6}p9u0AreiGauxn7JBEa-2w&d=!*TLJ49`U@D7%2ppIh)ynMaAE2Q4dl@47cNu{9 z&3vT#pG$#%hrXzXsj=&Ss*0;W`Jo^mcy4*L8b^sSi;H{*`zW9xX2HAtQ*sO|x$c6UbRA(7*9=;D~(%wfo(Z6#s$S zuFk`dr%DfVX5KC|Af8@AIr8@OAVj=6iX!~8D_P>p7>s!Hj+X0_t}Y*T4L5V->A@Zx zcm1wN;TNq=h`5W&>z5cNA99U1lY6+!!u$ib|41VMcJk8`+kP{PEOUvc@2@fW(bh5pp6>C3T55@XlpsAd#vn~__3H;Dz2w=t9v&{v*)1m4)vX;4 zX4YAjM66?Z7kD@XX{e`f1t_ZvYyi*puSNhVPq%jeyBteaOHo7vOr8!qqp7wV;)%jtD5>}-a?xavZ;i|2P3~7c)vP2O#Fb`Y&Kce zQNr7%fr4#S)OOV-1piOf7NgQvR{lcvZ*SNbLMq(olrdDC6su;ubp5un!&oT=jVTC3uTw7|r;@&y*s)a<{J zkzG(PApmMCpMmuh6GkM_`AsBE@t~)EDcq1AJ~N@7bqyW_i!mtHGnVgBA`Dxi^P93i z5R;}AQ60wy=Q2GUnSwz+W6C^}qn`S-lY7=J(3#BlOK%pCl=|RVWhC|IDj1E#+|M{TV0vE;vMZLy7KpD1$Yk zi0!9%qy8>CyrcRK`juQ)I};r)5|_<<9x)32b3DT1M`>v^ld!yabX6@ihf`3ZVTgME zfy(l-ocFuZ(L&OM4=1N#Mrrm_<>1DZpoWTO70U8+x4r3BpqH6z@(4~sqv!A9_L}@7 z7o~;|?~s-b?ud&Wx6==9{4uTcS|0-p@dKi0y#tPm2`A!^o3fZ8Uidxq|uz2vxf;wr zM^%#9)h^R&T;}cxVI(XX7kKPEVb);AQO?cFT-ub=%lZPwxefymBk+!H!W(o(>I{jW z$h;xuNUr#^0ivvSB-YEbUqe$GLSGrU$B3q28&oA55l)ChKOrwiTyI~e*uN;^V@g-Dm4d|MK!ol8hoaSB%iOQ#i_@`EYK_9ZEjFZ8Ho7P^er z^2U6ZNQ{*hcEm?R-lK)pD_r(e=Jfe?5VkJ$2~Oq^7YjE^5(6a6Il--j@6dBHx2Ulq z!%hz{d-S~i9Eo~WvQYDt7O7*G9CP#nrKE#DtIEbe_uxptcCSmYZMqT2F}7Kw0AWWC zPjwo0IYZ6klc(h9uL|NY$;{SGm4R8Bt^^q{e#foMxfCSY^-c&IVPl|A_ru!ebwR#7 z3<4+nZL(mEsU}O9e`^XB4^*m)73hd04HH%6ok^!;4|JAENnEr~%s6W~8KWD)3MD*+ zRc46yo<}8|!|yW-+KulE86aB_T4pDgL$XyiRW(OOcnP4|2;v!m2fB7Hw-IkY#wYfF zP4w;k-RInWr4fbz=X$J;z2E8pvAuy9kLJUSl8_USi;rW`kZGF?*Ur%%(t$^{Rg!=v zg;h3@!Q$eTa7S0#APEDHLvK%RCn^o0u!xC1Y0Jg!Baht*a4mmKHy~88md{YmN#x) zBOAp_i-z2h#V~*oO-9k(BizR^l#Vm%uSa^~3337d;f=AhVp?heJ)nlZGm`}D(U^2w z#vC}o1g1h?RAV^90N|Jd@M00PoNUPyA?@HeX0P7`TKSA=*4s@R;Ulo4Ih{W^CD{c8 ze(ipN{CAXP(KHJ7UvpOc@9SUAS^wKo3h-}BDZu}-qjdNlVtp^Z{|CxKOEo?tB}-4; zEXyDzGbXttJ3V$lLo-D?HYwZm7vvwdRo}P#KVF>F|M&eJ44n*ZO~0)#0e0Vy&j00I z{%IrnUvKp70P?>~J^$^0Wo%>le>re2ZSvRfes@dC-*e=DD1-j%<$^~4^4>Id5w^Fr z{RWL>EbUCcyC%1980kOYqZAcgdz5cS8c^7%vvrc@CSPIx;X=RuodO2dxk17|am?HJ@d~Mp_l8H?T;5l0&WGFoTKM{eP!L-a0O8?w zgBPhY78tqf^+xv4#OK2I#0L-cSbEUWH2z+sDur85*!hjEhFfD!i0Eyr-RRLFEm5(n z-RV6Zf_qMxN5S6#8fr9vDL01PxzHr7wgOn%0Htmvk9*gP^Um=n^+7GLs#GmU&a#U^4jr)BkIubQO7oUG!4CneO2Ixa`e~+Jp9m{l6apL8SOqA^ zvrfEUPwnHQ8;yBt!&(hAwASmL?Axitiqvx%KZRRP?tj2521wyxN3ZD9buj4e;2y6U zw=TKh$4%tt(eh|y#*{flUJ5t4VyP*@3af`hyY^YU3LCE3Z|22iRK7M7E;1SZVHbXF zKVw!L?2bS|kl7rN4(*4h2qxyLjWG0vR@`M~QFPsf^KParmCX;Gh4OX6Uy9#4e_%oK zv1DRnfvd$pu(kUoV(MmAc09ckDiuqS$a%!AQ1Z>@DM#}-yAP$l`oV`BDYpkqpk(I|+qk!yoo$TwWr6dRzLy(c zi+qbVlYGz0XUq@;Fm3r~_p%by)S&SVWS+wS0rC9bk^3K^_@6N5|2rtF)wI>WJ=;Fz zn8$h<|Dr%kN|nciMwJAv;_%3XG9sDnO@i&pKVNEfziH_gxKy{l zo`2m4rnUT(qenuq9B0<#Iy(RPxP8R)=5~9wBku=%&EBoZ82x1GlV<>R=hIqf0PK!V zw?{z9e^B`bGyg2nH!^x}06oE%J_JLk)^QyHLipoCs2MWIqc>vaxsJj(=gg1ZSa=u{ zt}od#V;e7sA4S(V9^<^TZ#InyVBFT(V#$fvI7Q+pgsr_2X`N~8)IOZtX}e(Bn(;eF zsNj#qOF_bHl$nw5!ULY{lNx@93Fj}%R@lewUuJ*X*1$K`DNAFpE z7_lPE+!}uZ6c?+6NY1!QREg#iFy=Z!OEW}CXBd~wW|r_9%zkUPR0A3m+@Nk%4p>)F zXVut7$aOZ6`w}%+WV$te6-IX7g2yms@aLygaTlIv3=Jl#Nr}nN zp|vH-3L03#%-1-!mY`1z?+K1E>8K09G~JcxfS)%DZbteGQnQhaCGE2Y<{ut#(k-DL zh&5PLpi9x3$HM82dS!M?(Z zEsqW?dx-K_GMQu5K54pYJD=5+Rn&@bGjB?3$xgYl-|`FElp}?zP&RAd<522c$Rv6} zcM%rYClU%JB#GuS>FNb{P2q*oHy}UcQ-pZ2UlT~zXt5*k-ZalE(`p7<`0n7i(r2k{ zb84&^LA7+aW1Gx5!wK!xTbw0slM?6-i32CaOcLC2B>ZRI16d{&-$QBEu1fKF0dVU>GTP05x2>Tmdy`75Qx! z^IG;HB9V1-D5&&)zjJ&~G}VU1-x7EUlT3QgNT<&eIDUPYey$M|RD6%mVkoDe|;2`8Z+_{0&scCq>Mh3hj|E*|W3;y@{$qhu77D)QJ` znD9C1AHCKSAHQqdWBiP`-cAjq7`V%~JFES1=i-s5h6xVT<50kiAH_dn0KQB4t*=ua zz}F@mcKjhB;^7ka@WbSJFZRPeYI&JFkpJ-!B z!ju#!6IzJ;D@$Qhvz9IGY5!%TD&(db3<*sCpZ?U#1^9RWQ zs*O-)j!E85SMKtoZzE^8{w%E0R0b2lwwSJ%@E}Lou)iLmPQyO=eirG8h#o&E4~eew z;h><=|4m0$`ANTOixHQOGpksXlF0yy17E&JksB4_(vKR5s$Ve+i;gco2}^RRJI+~R zWJ82WGigLIUwP!uSELh3AAs9HmY-kz=_EL-w|9}noKE#(a;QBpEx9 z4BT-zY=6dJT>72Hkz=9J1E=}*MC;zzzUWb@x(Ho8cU_aRZ?fxse5_Ru2YOvcr?kg&pt@v;{ai7G--k$LQtoYj+Wjk+nnZty;XzANsrhoH#7=xVqfPIW(p zX5{YF+5=k4_LBnhLUZxX*O?29olfPS?u*ybhM_y z*XHUqM6OLB#lyTB`v<BZ&YRs$N)S@5Kn_b3;gjz6>fh@^j%y2-ya({>Hd@kv{CZZ2e)tva7gxLLp z`HoGW);eRtov~Ro5tetU2y72~ zQh>D`@dt@s^csdfN-*U&o*)i3c4oBufCa0e|BwT2y%Y~=U7A^ny}tx zHwA>Wm|!SCko~UN?hporyQHRUWl3djIc722EKbTIXQ6>>iC!x+cq^sUxVSj~u)dsY zW8QgfZlE*2Os%=K;_vy3wx{0u!2%A)qEG-$R^`($%AOfnA^LpkB_}Dd7AymC)zSQr z>C&N8V57)aeX8ap!|7vWaK6=-3~ko9meugAlBKYGOjc#36+KJwQKRNa_`W@7;a>ot zdRiJkz?+QgC$b}-Owzuaw3zBVLEugOp6UeMHAKo2$m4w zpw?i%Lft^UtuLI}wd4(-9Z^*lVoa}11~+0|Hs6zAgJ01`dEA&^>Ai=mr0nC%eBd_B zzgv2G_~1c1wr*q@QqVW*Wi1zn=}KCtSwLjwT>ndXE_Xa22HHL_xCDhkM( zhbw+j4uZM|r&3h=Z#YrxGo}GX`)AZyv@7#7+nd-D?BZV>thtc|3jt30j$9{aIw9)v zDY)*fsSLPQTNa&>UL^RWH(vpNXT7HBv@9=*=(Q?3#H*crA2>KYx7Ab?-(HU~a275)MBp~`P)hhzSsbj|d`aBe(L*(;zif{iFJu**ZR zkL-tPyh!#*r-JVQJq>5b0?cCy!uSKef+R=$s3iA7*k*_l&*e!$F zYwGI;=S^0)b`mP8&Ry@{R(dPfykD&?H)na^ihVS7KXkxb36TbGm%X1!QSmbV9^#>A z-%X>wljnTMU0#d;tpw?O1W@{X-k*>aOImeG z#N^x?ehaaQd}ReQykp>i;92q@%$a!y1PNyPYDIvMm& zyYVwn;+0({W@3h(r&i#FuCDE)AC(y&Vu>4?1@j0|CWnhHUx4|zL7cdaA32RSk?wl% zMK^n42@i5AU>f70(huWfOwaucbaToxj%+)7hnG^CjH|O`A}+GHZyQ-X57(WuiyRXV zPf>0N3GJ<2Myg!sE4XJY?Z7@K3ZgHy8f7CS5ton0Eq)Cp`iLROAglnsiEXpnI+S8; zZn>g2VqLxi^p8#F#Laf3<00AcT}Qh&kQnd^28u!9l1m^`lfh9+5$VNv=?(~Gl2wAl zx(w$Z2!_oESg_3Kk0hUsBJ<;OTPyL(?z6xj6LG5|Ic4II*P+_=ac7KRJZ`(k2R$L# zv|oWM@116K7r3^EL*j2ktjEEOY9c!IhnyqD&oy7+645^+@z5Y|;0+dyR2X6^%7GD* zXrbPqTO}O={ z4cGaI#DdpP;5u?lcNb($V`l>H7k7otl_jQFu1hh>=(?CTPN#IPO%O_rlVX}_Nq;L< z@YNiY>-W~&E@=EC5%o_z<^3YEw)i_c|NXxHF{=7U7Ev&C`c^0Z4-LGKXu*Hkk&Av= zG&RAv{cR7o4${k~f{F~J48Ks&o(D@j-PQ2`LL@I~b=ifx3q!p6`d>~Y!<-^mMk3)e zhi1;(YLU5KH}zzZNhl^`0HT(r`5FfmDEzxa zk&J7WQ|!v~TyDWdXQ)!AN_Y%xM*!jv^`s)A`|F%;eGg27KYsrCE2H}7*r)zvum6B{ z$k5Har9pv!dcG%f|3hE(#hFH+12RZPycVi?2y`-9I7JHryMn3 z9Y8?==_(vOAJ7PnT<0&85`_jMD0#ipta~Q3M!q5H1D@Nj-YXI$W%OQplM(GWZ5Lpq z-He6ul|3<;ZQsqs!{Y7x`FV@pOQc4|N;)qgtRe(Uf?|YqZv^$k8On7DJ5>f2%M=TV zw~x}9o=mh$JVF{v4H5Su1pq66+mhTG6?F>Do}x{V(TgFwuLfvNP^ijkrp5#s4UT!~ zEU7pr8aA)2z1zb|X9IpmJykQcqI#(rS|A4&=TtWu@g^;JCN`2kL}%+K!KlgC z>P)v+uCeI{1KZpewf>C=?N7%1e10Y3pQCZST1GT5fVyB1`q)JqCLXM zSN0qlreH1=%Zg-5`(dlfSHI&2?^SQdbEE&W4#%Eve2-EnX>NfboD<2l((>>34lE%) zS6PWibEvuBG7)KQo_`?KHSPk+2P;`}#xEs}0!;yPaTrR#j(2H|#-CbVnTt_?9aG`o z(4IPU*n>`cw2V~HM#O`Z^bv|cK|K};buJ|#{reT8R)f+P2<3$0YGh!lqx3&a_wi2Q zN^U|U$w4NP!Z>5|O)>$GjS5wqL3T8jTn%Vfg3_KnyUM{M`?bm)9oqZP&1w1)o=@+(5eUF@=P~ zk2B5AKxQ96n-6lyjh&xD!gHCzD$}OOdKQQk7LXS-fk2uy#h{ktqDo{o&>O!6%B|)` zg?|JgcH{P*5SoE3(}QyGc=@hqlB5w;bnmF#pL4iH`TSuft$dE5j^qP2S)?)@pjRQZ zBfo6g>c!|bN-Y|(Wah2o61Vd|OtXS?1`Fu&mFZ^yzUd4lgu7V|MRdGj3e#V`=mnk- zZ@LHn?@dDi=I^}R?}mZwduik!hC%=Hcl56u{Wrk1|1SxlgnzG&e7Vzh*wNM(6Y!~m z`cm8Ygc1$@z9u9=m5vs1(XXvH;q16fxyX4&e5dP-{!Kd555FD6G^sOXHyaCLka|8j zKKW^E>}>URx736WWNf?U6Dbd37Va3wQkiE;5F!quSnVKnmaIRl)b5rM_ICu4txs+w zj}nsd0I_VG^<%DMR8Zf}vh}kk;heOQTbl ziEoE;9@FBIfR7OO9y4Pwyz02OeA$n)mESpj zdd=xPwA`nO06uGGsXr4n>Cjot7m^~2X~V4yH&- zv2llS{|und45}Pm1-_W@)a-`vFBpD~>eVP(-rVHIIA|HD@%7>k8JPI-O*<7X{L*Ik zh^K`aEN!BteiRaY82FVo6<^8_22=aDIa8P&2A3V<(BQ;;x8Zs-1WuLRWjQvKv1rd2 zt%+fZ!L|ISVKT?$3iCK#7whp|1ivz1rV*R>yc5dS3kIKy_0`)n*%bfNyw%e7Uo}Mnnf>QwDgeH$X5eg_)!pI4EJjh6?kkG2oc6Af0py z(txE}$ukD|Zn=c+R`Oq;m~CSY{ebu9?!is}01sOK_mB?{lSY33E=!KkKtMeI*FO2b z%95awv9;Z|UDp3xm+aP*5I!R-_M2;GxeCRx3ATS0iF<_Do2Mi)Hk2 zjBF35VB>(oamIYjunu?g0O-?LuOvtfs5F(iiIicbu$HMPPF%F>pE@hIRjzT)>aa=m zwe;H9&+2|S!m74!E3xfO{l3E_ab`Q^tZ4yH9=~o2DUEtEMDqG=&D*8!>?2uao%w`&)THr z^>=L3HJquY>6)>dW4pCWbzrIB+>rdr{s}}cL_?#!sOPztRwPm1B=!jP7lQG|Iy6rP zVqZDNA;xaUx&xUt?Ox|;`9?oz`C0#}mc<1Urs#vTW4wd{1_r`eX=BeSV z_9WV*9mz>PH6b^z{VYQJ1nSTSqOFHE9u>cY)m`Q>=w1NzUShxcHsAxasnF2BG;NQ; zqL1tjLjImz_`q=|bAOr_i5_NEijqYZ^;d5y3ZFj6kCYakJh**N_wbfH;ICXq?-p#r z{{ljNDPSytOaG#7=yPmA&5gyYI%^7pLnMOw-RK}#*dk=@usL;|4US?{@K%7esmc&n z5$D*+l&C9)Bo@$d;Nwipd!68&+NnOj^<~vRcKLX>e03E|;to;$ndgR;9~&S-ly5gf z{rzj+j-g$;O|u?;wwxrEpD=8iFzUHQfl{B>bLHqH(9P zI59SS2PEBE;{zJUlcmf(T4DrcO?XRWR}?fekN<($1&AJTRDyW+D*2(Gyi?Qx-i}gy z&BpIO!NeVdLReO!YgdUfnT}7?5Z#~t5rMWqG+$N2n%5o#Np6ccNly}#IZQsW4?|NV zR9hrcyP(l#A+U4XcQvT;4{#i)dU>HK>aS!k1<3s2LyAhm2(!Nu%vRC9T`_yn9D+r} z1i&U~IcQ?4xhZYyH6WL-f%}qIhZkc&}n2N0PM| z6|XA9d-y;!`D{p;xu*gv7a|zaZ*MiQ)}zPzW4GB0mr)}N-DmB&hl1&x`2@sxN572_ zS)RdJyR%<7kW0v3Q_|57JKy&9tUdbqz}|hwn84}U*0r^jt6Ssrp+#1y=JBcZ+F`f(N?O0XL1OFGN`1-r?S<#t4*C9|y~e)!UYZ zRQ3M8m%~M)VriIvn~XzoP;5qeu(ZI>Y#r zAd)J)G9)*BeE%gmm&M@Olg3DI_zokjh9NvdGbT z+u4(Y&uC6tBBefIg~e=J#8i1Zxr>RT)#rGaB2C71usdsT=}mm`<#WY^6V{L*J6v&l z1^Tkr6-+^PA)yC;s1O^3Q!)Reb=fxs)P~I*?i&j{Vbb(Juc?La;cA5(H7#FKIj0Or zgV0BO{DUs`I9HgQ{-!g@5P^Vr|C4}~w6b=#`Zx0XcVSd?(04HUHwK(gJNafgQNB9Z zCi3TgNXAeJ+x|X|b@27$RxuYYuNSUBqo#uyiH6H(b~K*#!@g__4i%HP5wb<+Q7GSb zTZjJw96htUaGZ89$K_iBo4xEOJ#DT#KRu9ozu!GH0cqR>hP$nk=KXM%Y!(%vWQ#}s zy=O#BZ>xjUejMH^F39Bf0}>D}yiAh^toa-ts#gt6Mk9h1D<9_mGMBhLT0Ce2O3d_U znaTkBaxd-8XgwSp5)x-pqX5=+{cSuk6kyl@k|5DQ!5zLUVV%1X9vjY0gerbuG6nwZu5KDMdq(&UMLZ zy?jW#F6joUtVyz`Y?-#Yc0=i*htOFwQ3`hk$8oq35D}0m$FAOp#UFTV3|U3F>@N?d zeXLZCZjRC($%?dz(41e~)CN10qjh^1CdAcY(<=GMGk@`b1ptA&L*{L@_M{%Vd5b*x#b1(qh=7((<_l%ZUaHtmgq} zjchBdiis{Afxf@3CjPR09E*2#X(`W#-n`~6PcbaL_(^3tfDLk?Nb6CkW9v!v#&pWJ3iV-9hz zngp#Q`w`r~2wt&cQ9#S7z0CA^>Mzm7fpt72g<0y-KT{G~l-@L#edmjZQ}7{*$mLgSdJfS$Ge{hrD=mr;GD)uYq8}xS zT>(w_;}894Kb}(P5~FOpFIEjadhmxD(PsZbKwa-qxVa7Oc7~ebPKMeN(pCRzq8s@l z`|l^*X1eK1+Spz--WkSW_nK`Cs@JmkY4+p=U91nJoy{tSH;TzuIyS)Q_(S@;Iakua zpuDo5W54Mo;jY@Ly1dY)j|+M%$FJ0`C=FW#%UvOd&?p}0QqL20Xt!#pr8ujy6CA-2 zFz6Ex5H1i)c9&HUNwG{8K%FRK7HL$RJwvGakleLLo}tsb>t_nBCIuABNo$G--_j!gV&t8L^4N6wC|aLC)l&w04CD6Vc#h^(YH@Zs4nwUGkhc_-yt{dK zMZ<%$swLmUl8`E~RLihGt@J5v;r;vT&*Q!Cx zZ55-zpb;W7_Q{tf$mQvF61(K>kwTq0x{#Din||)B{+6O#ArLi)kiHWVC4`fOT&B(h zw&YV`J1|^FLx~9Q%r-SFhYl4PywI7sF2Q$>4o50~dfp5nn}XHv-_DM?RGs#+4gM;% znU>k=81G~f6u%^Z{bcX&sUv*h|L+|mNq=W43y@{~C zpL-TW3hYPs0^*OqS#KQwA^CGG_A-6#`_{1LBCD&*3nY0UHWJj1D|VP%oQlFxLllaA zVI@2^)HZ%E*=RbQcFOKIP7?+|_xVK+2oG(t_EGl2y;Ovox zZb^qVpe!4^reKvpIBFzx;Ji=PmrV>uu-Hb>`s?k?YZQ?>av45>i(w0V!|n?AP|v5H zm`e&Tgli#lqGEt?=(?~fy<(%#nDU`O@}Vjib6^rfE2xn;qgU6{u36j_+Km%v*2RLnGpsvS+THbZ>p(B zgb{QvqE?~50pkLP^0(`~K& zjT=2Pt2nSnwmnDFi2>;*C|OM1dY|CAZ5R|%SAuU|5KkjRM!LW_)LC*A zf{f>XaD+;rl6Y>Umr>M8y>lF+=nSxZX_-Z7lkTXyuZ(O6?UHw^q; z&$Zsm4U~}KLWz8>_{p*WQ!OgxT1JC&B&>|+LE3Z2mFNTUho<0u?@r^d=2 z-av!n8r#5M|F%l;=D=S1mGLjgFsiYAOODAR}#e^a8 zfVt$k=_o}kt3PTz?EpLkt54dY}kyd$rU zVqc9SN>0c z753j-gdN~UiW*FUDMOpYEkVzP)}{Ds*3_)ZBi)4v26MQr140|QRqhFoP=a|;C{#KS zD^9b-9HM11W+cb1Y)HAuk<^GUUo(ut!5kILBzAe)Vaxwu4Up!7Ql*#DDu z>EB84&xSrh>0jT!*X81jJQq$CRHqNj29!V3FN9DCx)~bvZbLwSlo3l^zPb1sqBnp) zfZpo|amY^H*I==3#8D%x3>zh#_SBf?r2QrD(Y@El!wa;Ja6G9Y1947P*DC|{9~nO& z*vDnnU!8(cV%HevsraF%Y%2{Z>CL0?64eu9r^t#WjW4~3uw8d}WHzsV%oq-T)Y z0-c!FWX5j1{1##?{aTeCW2b$PEnwe;t`VPCm@sQ`+$$L2=3kBR%2XU1{_|__XJ$xt zibjY2QlDVs)RgHH*kl&+jn*JqquF)k_Ypibo00lcc<2RYqsi-G%}k0r(N97H7JEn7@E3ZTH0JK>d8)E~A-D z!B&z9zJw0Bi^fgQZI%LirYaBKnWBXgc`An*qvO^*$xymqKOp(+3}IsnVhu?YnN7qz zNJxDN-JWd7-vIiv2M9ih>x3gNVY%DzzY~dCnA}76IRl!`VM=6=TYQ=o&uuE8kHqZT zoUNod0v+s9D)7aLJ|hVqL0li1hg)%&MAciI(4YJ=%D4H$fGQ&Lu-?@>>@pEgC;ERrL= zI^cS&3q8fvEGTJZgZwL5j&jp%j9U^Of6pR{wA^u=tVt#yCQepXNIbynGnuWbsC_EE zRyMFq{5DK692-*kyGy~An>AdVR9u___fzmmJ4;^s0yAGgO^h{YFmqJ%ZJ_^0BgCET zE6(B*SzeZ4pAxear^B-YW<%BK->X&Cr`g9_;qH~pCle# zdY|UB5cS<}DFRMO;&czbmV(?vzikf)Ks`d$LL801@HTP5@r><}$xp}+Ip`u_AZ~!K zT}{+R9Wkj}DtC=4QIqJok5(~0Ll&_6PPVQ`hZ+2iX1H{YjI8axG_Bw#QJy`6T>1Nn z%u^l`>XJ{^vX`L0 z1%w-ie!dE|!SP<>#c%ma9)8K4gm=!inHn2U+GR+~ zqZVoa!#aS0SP(|**WfQSe?cA=1|Jwk`UDsny%_y{@AV??N>xWekf>_IZLUEK3{Ksi zWWW$if&Go~@Oz)`#=6t_bNtD$d9FMBN#&97+XKa+K2C@I9xWgTE{?Xnhc9_KKPcujj@NprM@e|KtV_SR+ zSpeJ!1FGJ=Te6={;;+;a46-*DW*FjTnBfeuzI_=I1yk8M(}IwEIGWV0Y~wia;}^dg z{BK#G7^J`SE10z4(_Me=kF&4ld*}wpNs91%2Ute>Om`byv9qgK4VfwPj$`axsiZ)wxS4k4KTLb-d~!7I@^Jq`>?TrixHk|9 zqCX7@sWcVfNP8N;(T>>PJgsklQ#GF>F;fz_Rogh3r!dy*0qMr#>hvSua;$d z3TCZ4tlkyWPTD<=5&*bUck~J;oaIzSQ0E03_2x{?weax^jL3o`ZP#uvK{Z5^%H4b6 z%Kbp6K?>{;8>BnQy64Jy$~DN?l(ufkcs6TpaO&i~dC>0fvi-I^7YT#h?m;TVG|nba%CKRG%}3P*wejg) zI(ow&(5X3HR_xk{jrnkA-hbwxEQh|$CET9Qv6UpM+-bY?E!XVorBvHoU59;q<9$hK z%w5K-SK zWT#1OX__$ceoq0cRt>9|)v}$7{PlfwN}%Wh3rwSl;%JD|k~@IBMd5}JD#TOvp=S57 zae=J#0%+oH`-Av}a(Jqhd4h5~eG5ASOD)DfuqujI6p!;xF_GFcc;hZ9k^a7c%%h(J zhY;n&SyJWxju<+r`;pmAAWJmHDs{)V-x7(0-;E?I9FWK@Z6G+?7Py8uLc2~Fh1^0K zzC*V#P88(6U$XBjLmnahi2C!a+|4a)5Ho5>owQw$jaBm<)H2fR=-B*AI8G@@P-8I8 zHios92Q6Nk-n0;;c|WV$Q);Hu4;+y%C@3alP`cJ2{z~*m-@de%OKVgiWp;4Q)qf9n zJ!vmx(C=_>{+??w{U^Bh|LFJ<6t}Er<-Tu{C{dv8eb(kVQ4!fOuopTo!^x1OrG}0D zR{A#SrmN`=7T29bzQ}bwX8OUufW9d9T4>WY2n15=k3_rfGOp6sK0oj7(0xGaEe+-C zVuWa;hS*MB{^$=0`bWF(h|{}?53{5Wf!1M%YxVw}io4u-G2AYN|FdmhI13HvnoK zNS2fStm=?8ZpKt}v1@Dmz0FD(9pu}N@aDG3BY8y`O*xFsSz9f+Y({hFx;P_h>ER_& z`~{z?_vCNS>agYZI?ry*V96_uh;|EFc0*-x*`$f4A$*==p`TUVG;YDO+I4{gJGrj^ zn?ud(B4BlQr;NN?vaz_7{&(D9mfd z8esj=a4tR-ybJjCMtqV8>zn`r{0g$hwoWRUI3}X5=dofN){;vNoftEwX>2t@nUJro z#%7rpie2eH1sRa9i6TbBA4hLE8SBK@blOs=ouBvk{zFCYn4xY;v3QSM%y6?_+FGDn z4A;m)W?JL!gw^*tRx$gqmBXk&VU=Nh$gYp+Swu!h!+e(26(6*3Q!(!MsrMiLri`S= zKItik^R9g!0q7y$lh+L4zBc-?Fsm8`CX1+f>4GK7^X2#*H|oK}reQnT{Mm|0ar<+S zRc_dM%M?a3bC2ILD`|;6vKA`a3*N~(cjw~Xy`zhuY2s{(7KLB{S>QtR3NBQ3>vd+= z#}Q)AJr7Y_-eV(sMN#x!uGX08oE*g=grB*|bBs}%^3!RVA4f%m3=1f0K=T^}iI&2K zuM2GG5_%+#v-&V>?x4W9wQ|jE2Q7Be8mOyJtZrqn#gXy-1fF1P$C8+We&B*-pi#q5 zETp%H6g+%#sH+L4=ww?-h;MRCd2J9zwQUe4gHAbCbH08gDJY;F6F)HtWCRW1fLR;)ysGZanlz*a+|V&@(ipWdB!tz=m_0 z6F}`d$r%33bw?G*azn*}Z;UMr{z4d9j~s`0*foZkUPwpJsGgoR0aF>&@DC;$A&(av z?b|oo;`_jd>_5nye`DVOcMLr-*Nw&nA z82E8Dw^$Lpso)gEMh?N|Uc^X*NIhg=U%enuzZOGi-xcZRUZmkmq~(cP{S|*+A6P;Q zprIkJkIl51@ng)8cR6QSXJtoa$AzT@*(zN3M+6`BTO~ZMo0`9$s;pg0HE3C;&;D@q zd^0zcpT+jC%&=cYJF+j&uzX87d(gP9&kB9|-zN=69ymQS9_K@h3ph&wD5_!4q@qI@ zBMbd`2JJ2%yNX?`3(u&+nUUJLZ=|{t7^Rpw#v-pqD2_3}UEz!QazhRty%|Q~WCo7$ z+sIugHA%Lmm{lBP#bnu_>G}Ja<*6YOvSC;89z67M%iG0dagOt1HDpDn$<&H0DWxMU zxOYaaks6%R@{`l~zlZ*~2}n53mn2|O&gE+j*^ypbrtBv{xd~G(NF?Z%F3>S6+qcry z?ZdF9R*a;3lqX_!rI(Cov8ER_mOqSn6g&ZU(I|DHo7Jj`GJ}mF;T(vax`2+B8)H_D zD0I;%I?*oGD616DsC#j0x*p+ZpBfd=9gR|TvB)832CRhsW_7g&WI@zp@r7dhg}{+4f=(cO2s+)jg0x(*6|^+6W_=YIfSH0lTcK* z%)LyaOL6em@*-_u)}Swe8rU)~#zT-vNiW(D*~?Zp3NWl1y#fo!3sK-5Ek6F$F5l3| zrFFD~WHz1}WHmzzZ!n&O8rTgfytJG*7iE~0`0;HGXgWTgx@2fD`oodipOM*MOWN-} zJY-^>VMEi8v23ZlOn0NXp{7!QV3F1FY_URZjRKMcY(2PV_ms}EIC^x z=EYB5UUQ{@R~$2Mwiw$_JAcF+szKB*n(`MYpDCl>~ss54uDQ%Xf-8|dgO zY)B_qju=IaShS|XsQo=nSYxV$_vQR@hd~;qW)TEfU|BA0&-JSwO}-a*T;^}l;MgLM zz}CjPlJX|W2vCzm3oHw3vqsRc3RY=2()}iw_k2#eKf&VEP7TQ;(DDzEAUgj!z_h2Br;Z3u=K~LqM6YOrlh)v9`!n|6M-s z?XvA~y<5?WJ{+yM~uPh7uVM&g-(;IC3>uA}ud?B3F zelSyc)Nx>(?F=H88O&_70%{ATsLVTAp88F-`+|egQ7C4rpIgOf;1tU1au+D3 zlz?k$jJtTOrl&B2%}D}8d=+$NINOZjY$lb{O<;oT<zXoAp01KYG$Y4*=)!&4g|FL(!54OhR-?)DXC&VS5E|1HGk8LY;)FRJqnz zb_rV2F7=BGwHgDK&4J3{%&IK~rQx<&Kea|qEre;%A~5YD6x`mo>mdR)l?Nd%T2(5U z_ciT02-zt_*C|vn?BYDuqSFrk3R(4B0M@CRFmG{5sovIq4%8AhjXA5UwRGo)MxZlI zI%vz`v8B+#ff*XtGnciczFG}l(I}{YuCco#2E6|+5WJ|>BSDfz0oT+F z%QI^ixD|^(AN`MS6J$ zXlKNTFhb>KDkJp*4*LaZ2WWA5YR~{`={F^hwXGG*rJYQA7kx|nwnC58!eogSIvy{F zm1C#9@$LhK^Tl>&iM0wsnbG7Y^MnQ=q))MgApj4)DQt!Q5S`h+5a%c7M!m%)?+h65 z0NHDiEM^`W+M4)=q^#sk(g!GTpB}edwIe>FJQ+jAbCo#b zXmtd3raGJNH8vnqMtjem<_)9`gU_-RF&ZK!aIenv7B2Y0rZhon=2yh&VsHzM|`y|0x$Zez$bUg5Nqj?@~^ zPN43MB}q0kF&^=#3C;2T*bDBTyO(+#nZnULkVy0JcGJ36or7yl1wt7HI_>V7>mdud zv2II9P61FyEXZuF$=69dn%Z6F;SOwyGL4D5mKfW)q4l$8yUhv7|>>h_-4T*_CwAyu7;DW}_H zo>N_7Gm6eed=UaiEp_7aZko@CC61@(E1be&5I9TUq%AOJW>s^9w%pR5g2{7HW9qyF zh+ZvX;5}PN0!B4q2FUy+C#w5J?0Tkd&S#~94(AP4%fRb^742pgH7Tb1))siXWXHUT z1Wn5CG&!mGtr#jq6(P#!ck@K+FNprcWP?^wA2>mHA03W?kj>5b|P0ErXS) zg2qDTjQ|grCgYhrH-RapWCvMq5vCaF?{R%*mu}1)UDll~6;}3Q*^QOfj!dlt02lSzK z?+P)02Rrq``NbU3j&s*;<%i4Y>y9NK&=&KsYwvEmf5jwTG6?+Pu1q9M8lLlx)uZZ7 zizhr~e0ktGs-=$li-2jz^_48-jk**y&5u0`B2gc#i$T1~t+AS*kEfR*b{^Ec>2-F~ zKYRl&uQ5yO@EtAZX8ZSqx;8+AKf+CqhlUSpp*VfyBMv+%wxN5GukZEi^_to%MFRc0 zdXqJ*jk?#uYT6EJe446@(f6G4vhnxQP|pGeJ?-#|Ksq?g*ky=}x+Qnx+!<>Y(XStN zQIND`{KU}&l)E*ntI^}kJ=ly8DML{!(58Xk4_bzIc@v~e;>wKl_`7G%pGz~4KH*CTp;_|52)d!+ximd$|8v@zzEq%j68QXkgf$7eM~xdM5q5i z{?qFx_W|eq@L03bWJfjy^z@()-iCjzjREuf zb_a(yTz)ZKWCF%Lp>^2-%Q?*t{06}x#DLN3cO=i>h6#-a`z;<5rBGGM6GA(WqvRcX%Pn?Uvs1#e|ePSNJEC%+X(YI$x)`s$%>O#%}D9dgqWfq4yfVz^%FglokdFR}uJQhx|}_w`9Ulx38Ha>ZslKs58c-@IFI&f;?xM zbK>rKNfPFsf>%+k6%(A6=7Aac^_qrOCNqb3ZVJ;8pt!?1DR*ynJb#@II9h?)xB)A~ zm9Kk)Hy}!Z+W}i6ZJDy+?yY_=#kWrzgV)2eZAx_E=}Nh7*#<&mQz`Umfe$+l^P(xd zN}PA2qII4}ddCU+PN+yxkH%y!Qe(;iH3W%bwM3NKbU_saBo<8x9fGNtTAc_SizU=o zC3n2;c%LoU^j90Sz>B_p--Fzqv7x7*?|~-x{haH8RP)p|^u$}S9pD-}5;88pu0J~9 zj}EC`Q^Fw}`^pvAs4qOIuxKvGN@DUdRQ8p-RXh=3S#<`3{+Qv6&nEm)uV|kRVnu6f zco{(rJaWw(T0PWim?kkj9pJ)ZsUk9)dSNLDHf`y&@wbd;_ita>6RXFJ+8XC*-wsiN z(HR|9IF283fn=DI#3Ze&#y3yS5;!yoIBAH(v}3p5_Zr+F99*%+)cp!Sy8e+lG?dOc zuEz<;3X9Z5kkpL_ZYQa`sioR_@_cG z8tT~GOSTWnO~#?$u)AcaBSaV7P~RT?Nn8(OSL1RmzPWRWQ$K2`6*)+&7^zZBeWzud z*xb3|Fc~|R9eH+lQ#4wF#c;)Gka6lL(63C;>(bZob!i8F-3EhYU3|6-JBC0*5`y0| zBs!Frs=s!Sy0qmQNgIH|F`6(SrD1js2prni_QbG9Sv@^Pu2szR9NZl8GU89gWWvVg z2^-b*t+F{Nt>v?js7hnlC`tRU(an0qQG7;h6T~ z-`vf#R-AE$pzk`M{gCaia}F`->O2)60AuGFAJg> z*O2IZqTx=AzDvC49?A92>bQLdb&32_4>0Bgp0ESXXnd4B)!$t$g{*FG%HYdt3b3a^J9#so%BJMyr2 z{y?rzW!>lr097b9(75#&4&@lkB1vT*w&0E>!dS+a|ZOu6t^zro2tiP)bhcNNxn zbJs3_Fz+?t;4bkd8GfDI7ccJ5zU`Bs~ zN~bci`c`a%DoCMel<-KUCBdZRmew`MbZEPYE|R#|*hhvhyhOL#9Yt7$g_)!X?fK^F z8UDz)(zpsvriJ5aro5>qy`Fnz%;IR$@Kg3Z3EE!fv9CAdrAym6QU82=_$_N5*({_1 z7!-=zy(R{xg9S519S6W{HpJZ8Is|kQ!0?`!vxDggmslD59)>iQ15f z7J8NqdR`9f8H|~iFGNsPV!N)(CC9JRmzL9S}7U-K@`X893f3f<8|8Ls!^eA^#(O6nA+ByFIXcz_WLbfeG|nHJ5_sJJ^gNJ%SI9#XEfNRbzV+!RkI zXS$MOVYb2!0vU}Gt7oUy*|WpF^*orBot~b2J@^be?Gq;U%#am8`PmH-UCFZ&uTJlnetYij0z{K1mmivk$bdPbLodu;-R@@#gAV!=d%(caz$E?r zURX0pqAn7UuF6dULnoF1dZ$WM)tHAM{eZK6DbU1J`V5Dw<;xk}Nl`h+nfMO_Rdv z3SyOMzAbYaD;mkxA7_I_DOs#Bk;e5D%gsS3q)hlmi1w{FsjKNJE22`AjmNiAPRnIc zcIkN25;rOn3FipAFd(PnlK9{03w6Q<(68#1Jw`{axEGQE{Ac>^U$h);h2ADICmaNxrfpb`Jdr*)Y1SicpYKCFv$3vf~;5aW>n^7QGa63MJ z;B1+Z>WQ615R2D8JmmT`T{QcgZ+Kz1hTu{9FOL}Q8+iFx-Vyi}ZVVcGjTe>QfA`7W zFoS__+;E_rQIQxd(Bq4$egKeKsk#-9=&A!)(|hBvydsr5ts0Zjp*%*C0lM2sIOx1s zg$xz?Fh?x!P^!vWa|}^+SY8oZHub7f;E!S&Q;F?dZmvBxuFEISC}$^B_x*N-xRRJh zn4W*ThEWaPD*$KBr8_?}XRhHY7h^U1aN6>m=n~?YJQd8+!Uyq_3^)~4>XjelM&!c9 zCo|0KsGq7!KsZ~9@%G?i>LaU7#uSTMpypocm*oqJHR|wOgVWc7_8PVuuw>x{kEG4T z$p^DV`}jUK39zqFc(d5;N+M!Zd3zhZN&?Ww(<@AV-&f!v$uV>%z+dg9((35o@4rqLvTC-se@hkn^6k7+xHiK-vTRvM8{bCejbU;1@U=*r}GTI?Oc$!b6NRcj83-zF; z=TB#ESDB`F`jf4)z=OS76Se}tQDDHh{VKJk#Ad6FDB_=afpK#pyRkGrk~OuzmQG)} z*$t!nZu$KN&B;|O-aD=H<|n6aGGJZ=K9QFLG0y=Jye_ElJFNZJT;fU8P8CZcLBERjioAOC0Vz_pIXIc};)8HjfPwNy zE!g|lkRv3qpmU?shz(BBt5%TbpJC3HzP9!t7k*Fh48!-HlJ4TTgdCr3rCU!iF}kgu z4Qs;K@XOY~4f~N}Jl8V_mGbwzvNLbl&0e9UG4W;kvjTK|5`-Ld+eQ6YRF`N0ct%u% z^3J_{7r#_W1zm|>IPN!yWCRrN)N!7v`~ptNkIXKipQ6ogFvcnI5ugxdoa{d;uD67g zgo^}QuZRkB540Vc!@c80(wFG=$ct}oHq(#W0+-XX(;Rrt`x=<45X}ficNtI2(&}=~ zb(!}tNz?s`wm{gK?2tdf+OEF;tzx<(3fMd7_tM@Ghs$Z(Os-H(kYq#qB|J-aC9Ku?fsWwJhB36c)A zu|a7ZF?V8X7l2g5~xqZf>2=6Dsi5lfo zKIRL&@MLJyaBE)V_9=pJYu%U2wxR*-(0MI5_|yqP`?h@cks(5LR@XUKLMI_xuVtiu zRvpDS8MyUMRFM6`P+Sjc!A_e^H38Qu7b{b7QZ>NHyA6k-YYygQuW&C_OGO(7V7?}r)zedSVpBI zuk29Z4GW3C0GpfozbZQya454sjt@ndQmsp=DA&@sWw&xmOlDk1JIcMNp~-ES$&A~k zG#W(6hBj?!Fu8Q4WYexoSBa8_5=v20xnx6H?e;$t)5|f&{7=vOye^&3_c-Ug?|a@e z=X`&qT_5B7N9vZoPBhXOTEDV;4&x2Je4}T(UB~O-$D#CjX77$R?RZ*`ed~$G;$4YS z4n*|Pop(!NN79Hk2}U#cfEEwdxM)xQm}$~rV03xc=#U@@Y*}qEmot5KvDb=8{!E-n zl4p?}&g2h^sUGyTcGh=0aQzQb*k;K;dvbeZUgmwEv>%#(EPtj=gHKdi|E8@w+|>KC zxEU>b>P+9Xf}pEyQK(}#QrBG4Jaf!iE!qpMbTu>gb!gtdq<`@xO+roQl+S_7)!G(% zdy)$iGmJ1cwP?F=IyyV1-$|kf|EKM3B@I&lZ%NI@VV;*mQdLWjc#t|Vbk_Q~>&O03 zIcSr$(qLAINj7a z;!||v&1D5SX#X@5jNd}jUsi-CH_Scjyht&}q2p*CJCC-`&NyXf)vD5{e!HO629D-O z%bZelTcq=DoRX>zeWCa^RmR3*{x9;3lZ75M#S)!W0bRIFH#P6b%{|HRSZ5!!I#s)W z_|XXZQ<0_`>b^^0Z>LU64Yg1w)8}#M^9se(OZ9~baZ7fsKFc;EtnB>kesci#>=icG zuHdjax2^=!_(9?0l7;G7^-}9>Y#M zm;9*GT~dBuYWdk49%mZM0=H#FY1)}7NE5DE_vsqrA0`?0R0q535qHjWXcl|gz9Fq$ zMKxgL;68l!gm3y0durIr3LHv~y*ABm` zYhQG0UW#hg@*A{&G!;$FS43}rIF$e6yRdGJWVR<}uuJ_5_8qa3xaHH^!VzUteVp;> z<0`M>3tnY$ZFb$(`0sg93TwGyP;`9UYUWxO&CvAnSzei&ap))NcW;R`tA=y^?mBmG+M*&bqW5kL$V(O;(p)aEk`^ci?2Jwxu>0sy>a7+Wa9t z5#I2o;+gr^9^&km^z7>xJWbN&Ft>Vna34E zI@BBzwX)R}K3SL?)enrDJ45QLt;-7CFJk{`cF3L4Z^CtG_r5)0)HV>BOYPIUh#D%| zYQAu31f{bm-D*`_k7DTTr?Nkw_gY%J1cb2&TdtibY?V=|SSIOlA;|5C!2@?YQ z-$?G0jj^mG|MP>DmbF7}T~C$H6=CpZ~hd zZ1C|xV@=h#^~`3LSCnmI(vZ|5r3>eq5*UB)dhdy``*gKY3Eg%jSK8I-`G+OWWlD)T zt$wSQ=||lSkiKy}YF-k}@W9EiS?)z`hK{R!dd-$BCJvBtAN-yXn3njU$MisEtp!?Q z%Vk-*(wy9dd15(-WFw_&^tT;;IpF?ox1`Qq3-0zVTk+$W_?q}GfAQlPcrB^?&tWSI z2BB!K=sH7FUYmXa_dcV^Z3>5z8}~W{S!$jVR_3hu_|wl2|gmRH8ftn^z@fW75*;-`;wU+fY+BR_yx6BZnE5_Hna({jrPiubRp$jZ=T=t$hx&NeCV1!vuCcl4PJ0p0Fjp>6K} zHkoD1gQk=P2hYcT%)cJ2Q5WuA|5_x+dX0%hnozfTF>$#Wz~X!MY>){H4#fB#7^ID* z1*o2Hzp}?WVs&gbS?Uq(CT0sP+F)u9{xfgg6o_{8J#m;|NeJqDHhb(Q8%z8aM_qeM zn83>d`uDd47WIuKp78JBYo2SYupGcNXIzeou^eMY`@%Bv8elZ>q~3uq#~IX)g%g;h zoUXymEd>|kVsMkyb&1l~lrE-`w(0PObapYa35DJ4Y03Jv_!DKp}0HTbOgZRM=;PSsuAJJJ1 zItc+tu9;ANG;qHaCI|T85!euhFK~VK^G2LZV1+cbzS?>ar@>emg;JTI5VAn1g5U~| zU=p&k0OlSzc$U=s#9_uL3&n|6A1X$XvrE9vFV@`A4G#!D1QcFCeE`F2N(deJx>)*A z$XIW0P~-NbAd=5i6`s<~(vAQX9t$dbVqc5|E|CHRtb$1(l&KSNh_t2#k_l95KnP86 z)ns_DGspv-M0z0#h2a+*oH|{5~j{ zXGD=}cLrBSESQ0u$XmQlFfWMCAWaS;wKK%#aSSYK=qljBiY(s zT$v;We24&$w=avIILsMt0%1fDyah|AlLNg#WL$Lu)tf}YfqO%+pH~QC*bZO4aM*i9 zrPFf|5!hv@XY8CzaFh*Dy9vH|2fKKr(@x}`L#9^*vOae|lk`adG#oZZAyk|TOV8`9L zc-sQu%y1MQes&J?)a1}Zc*>-P!6j-T#75V$lLC!TuMB(!G-+D2;XptUxymSPFI-K&0x}B1?h$ z3-9**-9!);fwyiWB5gS$i;P~c=^}5-6G@{4TWDBRDc6(M|%qa-mS`z`u9kWo{Xl_uc;hXOkRd literal 0 HcmV?d00001 diff --git a/8week/racingcar/gradle/wrapper/gradle-wrapper.properties b/8week/racingcar/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..a4b44297 --- /dev/null +++ b/8week/racingcar/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/8week/racingcar/gradlew b/8week/racingcar/gradlew new file mode 100755 index 00000000..fbd7c515 --- /dev/null +++ b/8week/racingcar/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/8week/racingcar/gradlew.bat b/8week/racingcar/gradlew.bat new file mode 100644 index 00000000..5093609d --- /dev/null +++ b/8week/racingcar/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/8week/racingcar/settings.gradle b/8week/racingcar/settings.gradle new file mode 100644 index 00000000..563821bb --- /dev/null +++ b/8week/racingcar/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'racingcar' + diff --git a/8week/racingcar/src/main/java/Application.java b/8week/racingcar/src/main/java/Application.java new file mode 100644 index 00000000..e4975541 --- /dev/null +++ b/8week/racingcar/src/main/java/Application.java @@ -0,0 +1,7 @@ +import service.RacingGame; + +public class Application { + public static void main(String[] args) { + RacingGame.start(); + } +} diff --git a/8week/racingcar/src/main/java/domain/Car.java b/8week/racingcar/src/main/java/domain/Car.java new file mode 100644 index 00000000..41328194 --- /dev/null +++ b/8week/racingcar/src/main/java/domain/Car.java @@ -0,0 +1,54 @@ +package domain; + +public class Car implements Comparable { + private final String name; + private int position; + private static final int CONTROL_POINT = 4; + private static final int MAX_INPUT_LENGTH = 5; + + public Car(final String name) { + validateLength(name); + validateInput(name); + this.name = name; + this.position = 0; + } + + public void movePosition(int randomValue) { + if (isMoveAble(randomValue)) { + this.position = position + 1; + } + } + + private boolean isMoveAble(int randomValue) { + return randomValue > CONTROL_POINT; + } + + private void validateLength(String name) { + if (name.length() > MAX_INPUT_LENGTH) { + throw new IllegalArgumentException("[ERROR] 이름의 길이는 5를 넘을수 없습니다."); + } + } + + public int getPosition(){ + return position; + } + + public String getName() { + return name; + } + + private void validateInput(String buffer) { + if (buffer.contains(" ")) { + throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다."); + } + } + + public boolean isSamePosition(Car other) { + return other.position == this.position; + } + + @Override + public int compareTo(Car other) { + return this.position - other.position; + } +} diff --git a/8week/racingcar/src/main/java/domain/Cars.java b/8week/racingcar/src/main/java/domain/Cars.java new file mode 100644 index 00000000..48937677 --- /dev/null +++ b/8week/racingcar/src/main/java/domain/Cars.java @@ -0,0 +1,52 @@ +package domain; + +import utils.RandomUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + + +public class Cars { + private final List cars; + private static final int START_NUMBER = 0; + private static final int FINISH_NUMBER = 10; + + public Cars (List carNames) { + validateCars(carNames); + this.cars = carNames.stream() + .map(carName->new Car(carName)) + .collect(Collectors.toList()); + } + + private void validateCars(List carNames) { + Boolean value = (int) carNames.stream() + .distinct() + .count() != carNames.size(); + if (value) { + throw new IllegalArgumentException("[ERROR] 이름 중복"); + } + } + + public List getCars() { + return Collections.unmodifiableList(this.cars); + } + + public void moveCars() { + cars.stream() + .forEach(Car-> Car.movePosition(RandomUtils.randomIntGenerator(START_NUMBER, FINISH_NUMBER))); + } + + private Car findMaxPosition() { + return cars.stream() + .max(Car::compareTo) + .orElseThrow(() -> new IllegalArgumentException("[ERROR] 차량 리스트가 비었습니다.")); + } + + public List getWinner() { + return cars.stream() + .filter(car -> car.isSamePosition(findMaxPosition())) + .collect(Collectors.toCollection(ArrayList::new)); + } +} diff --git a/8week/racingcar/src/main/java/domain/Number.java b/8week/racingcar/src/main/java/domain/Number.java new file mode 100644 index 00000000..4c87be0d --- /dev/null +++ b/8week/racingcar/src/main/java/domain/Number.java @@ -0,0 +1,22 @@ +package domain; + +public class Number { + private final int value; + + public Number(String value) { + validateNumber(value); + this.value = Integer.parseInt(value); + } + + private void validateNumber(String value) { + try { + Integer.parseInt(value); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("[ERROR] 시도 횟수는 숫자여야 한다."); + } + } + + public int getCount() { + return value; + } +} diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java new file mode 100644 index 00000000..a11c1388 --- /dev/null +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -0,0 +1,8 @@ +package service; + +public class RacingGame { + public static void start() { + RacingGameController controller = new RacingGameController(); + controller.run(); + } +} diff --git a/8week/racingcar/src/main/java/service/RacingGameController.java b/8week/racingcar/src/main/java/service/RacingGameController.java new file mode 100644 index 00000000..f12f5c0e --- /dev/null +++ b/8week/racingcar/src/main/java/service/RacingGameController.java @@ -0,0 +1,33 @@ +package service; + +import domain.Cars; +import domain.Number; + +import utils.Input; +import utils.View; +import java.util.List; + +public class RacingGameController { + private Cars createCar() { + List carNames = Input.stringInput(); + return new Cars(carNames); + } + + private Number createCount() { + return Input.numberInput(); + } + + public void run() { + Cars cars = createCar(); + Number count = createCount(); + int times = count.getCount(); + while (times-- > 0) { + cars.moveCars(); + cars.getCars().stream() + .forEach(Car -> View.carStatusView(Car)); + View.spacingWord(); + } + View.resultView(cars.getWinner()); + } +} + diff --git a/8week/racingcar/src/main/java/utils/Input.java b/8week/racingcar/src/main/java/utils/Input.java new file mode 100644 index 00000000..0c3bd4b3 --- /dev/null +++ b/8week/racingcar/src/main/java/utils/Input.java @@ -0,0 +1,37 @@ +package utils; + +import domain.Number; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; + +public class Input { + private static final String SPLIT_RULE = ","; + private static final BufferedReader BUFFERED_READER = new BufferedReader(new InputStreamReader(System.in)); + + private Input() {}; + + public static List stringInput() { + try { + System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); + String buffer = BUFFERED_READER.readLine(); + return Arrays.asList(buffer.split(SPLIT_RULE)); + } catch (IOException e) { + throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다."); + } + } + + public static Number numberInput() { + try { + System.out.println("시도할 회수는 몇회인가요?"); + String buffer = BUFFERED_READER.readLine(); + Number number = new Number(buffer); + return number; + } catch (IOException e) { + throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다."); + } + } +} diff --git a/8week/racingcar/src/main/java/utils/RandomUtils.java b/8week/racingcar/src/main/java/utils/RandomUtils.java new file mode 100644 index 00000000..ceff946b --- /dev/null +++ b/8week/racingcar/src/main/java/utils/RandomUtils.java @@ -0,0 +1,24 @@ +package utils; + +import java.util.Random; + +public class RandomUtils { + private static final Random RANDOM = new Random(); + + private RandomUtils() { + } + + public static int randomIntGenerator(final int startNumber, final int lastNumber) { + if (startNumber > lastNumber) { + throw new IllegalArgumentException(); + } + if (startNumber < 0) { + throw new IllegalArgumentException(); + } + if (startNumber == lastNumber) { + return startNumber; + } + return startNumber + RANDOM.nextInt(lastNumber - startNumber + 1); + } + +} diff --git a/8week/racingcar/src/main/java/utils/View.java b/8week/racingcar/src/main/java/utils/View.java new file mode 100644 index 00000000..c708060f --- /dev/null +++ b/8week/racingcar/src/main/java/utils/View.java @@ -0,0 +1,43 @@ +package utils; + +import domain.Car; + +import java.util.List; +import java.util.stream.Collectors; + +public class View { + private static final String FINAL_WINNER = "최종 우승자 : "; + private static final String COLON = " : "; + private static final String COMMA = ", "; + private static final String POSITION_VIEW = "-"; + + private View() {}; + + public static void distanceView(int position) { + while (position-- > 0){ + System.out.print(POSITION_VIEW); + } + System.out.println(); + } + + public static void carNameView(final String name){ + System.out.print(name + COLON); + } + + public static void resultView(final List cars){ + System.out.print(FINAL_WINNER); + String winner = cars.stream() + .map(Car::getName) + .collect(Collectors.joining(COMMA)); + System.out.println(winner); + } + + public static void carStatusView(Car car) { + View.carNameView(car.getName()); + View.distanceView(car.getPosition()); + } + + public static void spacingWord() { + System.out.println(); + } +} diff --git a/8week/racingcar/src/test/java/StreamTest.java b/8week/racingcar/src/test/java/StreamTest.java new file mode 100644 index 00000000..61e36dcf --- /dev/null +++ b/8week/racingcar/src/test/java/StreamTest.java @@ -0,0 +1,19 @@ +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class StreamTest { + @Test + public void 테스트() { + List name = new ArrayList<>(Arrays.asList("동현", "정윤", "태정", "문기", "윤지", "수연")); + List collects = name.stream() + .sorted() + .collect(Collectors.toList()); + for(String collect : collects) { + System.out.println(collect); + } + } +} From 465f86d182800bc9faffc1efd5d76e6b2fbd7334 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:27:26 +0900 Subject: [PATCH 05/18] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=8B=A8=EA=B3=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/service/RacingGame.java | 18 +++++++++++++++++- .../java/service/RacingGameController.java | 19 ++++--------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java index a11c1388..d763b11e 100644 --- a/8week/racingcar/src/main/java/service/RacingGame.java +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -1,8 +1,24 @@ package service; +import domain.Cars; +import domain.Number; +import utils.View; + public class RacingGame { + + private RacingGame() {}; + public static void start() { RacingGameController controller = new RacingGameController(); - controller.run(); + Cars cars = controller.createCar(); + Number count = controller.createCount(); + int times = count.getCount(); + while (times-- > 0) { + cars.moveCars(); + cars.getCars().stream() + .forEach(Car -> View.carStatusView(Car)); + View.spacingWord(); + } + View.resultView(cars.getWinner()); } } diff --git a/8week/racingcar/src/main/java/service/RacingGameController.java b/8week/racingcar/src/main/java/service/RacingGameController.java index f12f5c0e..cf524c49 100644 --- a/8week/racingcar/src/main/java/service/RacingGameController.java +++ b/8week/racingcar/src/main/java/service/RacingGameController.java @@ -5,29 +5,18 @@ import utils.Input; import utils.View; + import java.util.List; public class RacingGameController { - private Cars createCar() { + + public Cars createCar() { List carNames = Input.stringInput(); return new Cars(carNames); } - private Number createCount() { + public Number createCount() { return Input.numberInput(); } - - public void run() { - Cars cars = createCar(); - Number count = createCount(); - int times = count.getCount(); - while (times-- > 0) { - cars.moveCars(); - cars.getCars().stream() - .forEach(Car -> View.carStatusView(Car)); - View.spacingWord(); - } - View.resultView(cars.getWinner()); - } } From 931edf7afe44fe06187455351b14553c4c13b4c8 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:31:47 +0900 Subject: [PATCH 06/18] refactor: stringInput -> carNamesInput --- 8week/racingcar/src/main/java/service/RacingGameController.java | 2 +- 8week/racingcar/src/main/java/utils/Input.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/8week/racingcar/src/main/java/service/RacingGameController.java b/8week/racingcar/src/main/java/service/RacingGameController.java index cf524c49..daaa9662 100644 --- a/8week/racingcar/src/main/java/service/RacingGameController.java +++ b/8week/racingcar/src/main/java/service/RacingGameController.java @@ -11,7 +11,7 @@ public class RacingGameController { public Cars createCar() { - List carNames = Input.stringInput(); + List carNames = Input.carNamesInput(); return new Cars(carNames); } diff --git a/8week/racingcar/src/main/java/utils/Input.java b/8week/racingcar/src/main/java/utils/Input.java index 0c3bd4b3..dba2a9bf 100644 --- a/8week/racingcar/src/main/java/utils/Input.java +++ b/8week/racingcar/src/main/java/utils/Input.java @@ -14,7 +14,7 @@ public class Input { private Input() {}; - public static List stringInput() { + public static List carNamesInput() { try { System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); String buffer = BUFFERED_READER.readLine(); From c96dc5db60fd723ab85d98f410e74531d73c22be Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:33:39 +0900 Subject: [PATCH 07/18] =?UTF-8?q?refactor:=20numberInput=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/utils/Input.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/8week/racingcar/src/main/java/utils/Input.java b/8week/racingcar/src/main/java/utils/Input.java index dba2a9bf..267cef39 100644 --- a/8week/racingcar/src/main/java/utils/Input.java +++ b/8week/racingcar/src/main/java/utils/Input.java @@ -28,8 +28,7 @@ public static Number numberInput() { try { System.out.println("시도할 회수는 몇회인가요?"); String buffer = BUFFERED_READER.readLine(); - Number number = new Number(buffer); - return number; + return new Number(buffer); } catch (IOException e) { throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다."); } From 34fa670004fa1b9bc3269d774addef032f1edf98 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:37:27 +0900 Subject: [PATCH 08/18] =?UTF-8?q?refactor:=20CarNamesInput=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EB=A6=AC=ED=84=B4=ED=95=98=EA=B2=8C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/service/RacingGameController.java | 6 +----- 8week/racingcar/src/main/java/utils/Input.java | 5 +++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/8week/racingcar/src/main/java/service/RacingGameController.java b/8week/racingcar/src/main/java/service/RacingGameController.java index daaa9662..31f8209e 100644 --- a/8week/racingcar/src/main/java/service/RacingGameController.java +++ b/8week/racingcar/src/main/java/service/RacingGameController.java @@ -4,15 +4,11 @@ import domain.Number; import utils.Input; -import utils.View; - -import java.util.List; public class RacingGameController { public Cars createCar() { - List carNames = Input.carNamesInput(); - return new Cars(carNames); + return Input.carNamesInput(); } public Number createCount() { diff --git a/8week/racingcar/src/main/java/utils/Input.java b/8week/racingcar/src/main/java/utils/Input.java index 267cef39..5100fe31 100644 --- a/8week/racingcar/src/main/java/utils/Input.java +++ b/8week/racingcar/src/main/java/utils/Input.java @@ -1,5 +1,6 @@ package utils; +import domain.Cars; import domain.Number; import java.io.BufferedReader; @@ -14,11 +15,11 @@ public class Input { private Input() {}; - public static List carNamesInput() { + public static Cars carNamesInput() { try { System.out.println("경주할 자동차 이름을 입력하세요.(이름은 쉼표(,) 기준으로 구분)"); String buffer = BUFFERED_READER.readLine(); - return Arrays.asList(buffer.split(SPLIT_RULE)); + return new Cars(Arrays.asList(buffer.split(SPLIT_RULE))); } catch (IOException e) { throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다."); } From d478791c3c892e64ace550e0dbb83d4259b08a05 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:39:41 +0900 Subject: [PATCH 09/18] =?UTF-8?q?refactor:=20stream=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/service/RacingGame.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java index d763b11e..3258595d 100644 --- a/8week/racingcar/src/main/java/service/RacingGame.java +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -15,7 +15,8 @@ public static void start() { int times = count.getCount(); while (times-- > 0) { cars.moveCars(); - cars.getCars().stream() + cars.getCars() + .stream() .forEach(Car -> View.carStatusView(Car)); View.spacingWord(); } From 23b68c912aef12c64895ea3245bcfaac2f24f6f5 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:41:17 +0900 Subject: [PATCH 10/18] =?UTF-8?q?refactor:=20stream=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/domain/Cars.java | 2 +- 8week/racingcar/src/main/java/service/RacingGame.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/8week/racingcar/src/main/java/domain/Cars.java b/8week/racingcar/src/main/java/domain/Cars.java index 48937677..5c05206f 100644 --- a/8week/racingcar/src/main/java/domain/Cars.java +++ b/8week/racingcar/src/main/java/domain/Cars.java @@ -16,7 +16,7 @@ public class Cars { public Cars (List carNames) { validateCars(carNames); this.cars = carNames.stream() - .map(carName->new Car(carName)) + .map(Car::new) .collect(Collectors.toList()); } diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java index 3258595d..ec725691 100644 --- a/8week/racingcar/src/main/java/service/RacingGame.java +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -17,7 +17,7 @@ public static void start() { cars.moveCars(); cars.getCars() .stream() - .forEach(Car -> View.carStatusView(Car)); + .forEach(View::carStatusView); View.spacingWord(); } View.resultView(cars.getWinner()); From 98af31c56f9d72ad9a3c5597e5c2196c0a233026 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:44:40 +0900 Subject: [PATCH 11/18] =?UTF-8?q?refactor:=20car=20=EB=B3=80=EC=88=98,=20?= =?UTF-8?q?=EC=83=81=EC=88=98=20=EC=84=A0=EC=96=B8=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/domain/Car.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/8week/racingcar/src/main/java/domain/Car.java b/8week/racingcar/src/main/java/domain/Car.java index 41328194..aabe200d 100644 --- a/8week/racingcar/src/main/java/domain/Car.java +++ b/8week/racingcar/src/main/java/domain/Car.java @@ -1,10 +1,10 @@ package domain; public class Car implements Comparable { - private final String name; - private int position; private static final int CONTROL_POINT = 4; private static final int MAX_INPUT_LENGTH = 5; + private final String name; + private int position; public Car(final String name) { validateLength(name); From 4487e4abc64c58945e29b1d79e1ae64b8060734a Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:45:38 +0900 Subject: [PATCH 12/18] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20test=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/test/java/StreamTest.java | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 8week/racingcar/src/test/java/StreamTest.java diff --git a/8week/racingcar/src/test/java/StreamTest.java b/8week/racingcar/src/test/java/StreamTest.java deleted file mode 100644 index 61e36dcf..00000000 --- a/8week/racingcar/src/test/java/StreamTest.java +++ /dev/null @@ -1,19 +0,0 @@ -import org.junit.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class StreamTest { - @Test - public void 테스트() { - List name = new ArrayList<>(Arrays.asList("동현", "정윤", "태정", "문기", "윤지", "수연")); - List collects = name.stream() - .sorted() - .collect(Collectors.toList()); - for(String collect : collects) { - System.out.println(collect); - } - } -} From b7364f20ad7edb99c876354c5b60bb62582e32b7 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:47:12 +0900 Subject: [PATCH 13/18] =?UTF-8?q?refactor:=20cars=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98,=20stream=20->=20=EC=BB=AC=EB=A0=89=EC=85=98=20foreac?= =?UTF-8?q?h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/domain/Cars.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/8week/racingcar/src/main/java/domain/Cars.java b/8week/racingcar/src/main/java/domain/Cars.java index 5c05206f..357dc5d0 100644 --- a/8week/racingcar/src/main/java/domain/Cars.java +++ b/8week/racingcar/src/main/java/domain/Cars.java @@ -9,9 +9,9 @@ public class Cars { - private final List cars; private static final int START_NUMBER = 0; private static final int FINISH_NUMBER = 10; + private final List cars; public Cars (List carNames) { validateCars(carNames); @@ -34,8 +34,7 @@ public List getCars() { } public void moveCars() { - cars.stream() - .forEach(Car-> Car.movePosition(RandomUtils.randomIntGenerator(START_NUMBER, FINISH_NUMBER))); + cars.forEach(Car-> Car.movePosition(RandomUtils.randomIntGenerator(START_NUMBER, FINISH_NUMBER))); } private Car findMaxPosition() { From 225f8e5edf064f7b1ba10351d052f1f96767d08c Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Mon, 3 May 2021 19:52:00 +0900 Subject: [PATCH 14/18] =?UTF-8?q?refactor:=20cars=20=EC=BB=A8=EB=B2=A4?= =?UTF-8?q?=EC=85=98,=20racingGameController=20=EC=83=9D=EC=84=B1=EC=9E=90?= =?UTF-8?q?=20=EB=A7=89=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../racingcar/src/main/java/domain/Cars.java | 26 +++++++++---------- .../src/main/java/service/RacingGame.java | 5 ++-- .../java/service/RacingGameController.java | 6 +++-- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/8week/racingcar/src/main/java/domain/Cars.java b/8week/racingcar/src/main/java/domain/Cars.java index 357dc5d0..c9760b92 100644 --- a/8week/racingcar/src/main/java/domain/Cars.java +++ b/8week/racingcar/src/main/java/domain/Cars.java @@ -20,13 +20,10 @@ public Cars (List carNames) { .collect(Collectors.toList()); } - private void validateCars(List carNames) { - Boolean value = (int) carNames.stream() - .distinct() - .count() != carNames.size(); - if (value) { - throw new IllegalArgumentException("[ERROR] 이름 중복"); - } + public List getWinner() { + return cars.stream() + .filter(car -> car.isSamePosition(findMaxPosition())) + .collect(Collectors.toCollection(ArrayList::new)); } public List getCars() { @@ -37,15 +34,18 @@ public void moveCars() { cars.forEach(Car-> Car.movePosition(RandomUtils.randomIntGenerator(START_NUMBER, FINISH_NUMBER))); } + private void validateCars(List carNames) { + Boolean value = (int) carNames.stream() + .distinct() + .count() != carNames.size(); + if (value) { + throw new IllegalArgumentException("[ERROR] 이름 중복"); + } + } + private Car findMaxPosition() { return cars.stream() .max(Car::compareTo) .orElseThrow(() -> new IllegalArgumentException("[ERROR] 차량 리스트가 비었습니다.")); } - - public List getWinner() { - return cars.stream() - .filter(car -> car.isSamePosition(findMaxPosition())) - .collect(Collectors.toCollection(ArrayList::new)); - } } diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java index ec725691..8f2456ea 100644 --- a/8week/racingcar/src/main/java/service/RacingGame.java +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -9,9 +9,8 @@ public class RacingGame { private RacingGame() {}; public static void start() { - RacingGameController controller = new RacingGameController(); - Cars cars = controller.createCar(); - Number count = controller.createCount(); + Cars cars = RacingGameController.createCar(); + Number count = RacingGameController.createCount(); int times = count.getCount(); while (times-- > 0) { cars.moveCars(); diff --git a/8week/racingcar/src/main/java/service/RacingGameController.java b/8week/racingcar/src/main/java/service/RacingGameController.java index 31f8209e..12289d04 100644 --- a/8week/racingcar/src/main/java/service/RacingGameController.java +++ b/8week/racingcar/src/main/java/service/RacingGameController.java @@ -7,11 +7,13 @@ public class RacingGameController { - public Cars createCar() { + private RacingGameController() {}; + + public static Cars createCar() { return Input.carNamesInput(); } - public Number createCount() { + public static Number createCount() { return Input.numberInput(); } } From d6e5487717f6cc9998711aa8912f1939735b5c92 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Tue, 4 May 2021 12:12:06 +0900 Subject: [PATCH 15/18] =?UTF-8?q?refactor=20:=20View=EC=97=90=EA=B2=8C=20c?= =?UTF-8?q?ars=EB=A5=BC=20=EB=84=98=EA=B2=A8=20statusView=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/service/RacingGame.java | 4 +--- 8week/racingcar/src/main/java/utils/View.java | 11 ++++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java index 8f2456ea..e43c5d79 100644 --- a/8week/racingcar/src/main/java/service/RacingGame.java +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -14,9 +14,7 @@ public static void start() { int times = count.getCount(); while (times-- > 0) { cars.moveCars(); - cars.getCars() - .stream() - .forEach(View::carStatusView); + View.carStatusView(cars); View.spacingWord(); } View.resultView(cars.getWinner()); diff --git a/8week/racingcar/src/main/java/utils/View.java b/8week/racingcar/src/main/java/utils/View.java index c708060f..8fa461ff 100644 --- a/8week/racingcar/src/main/java/utils/View.java +++ b/8week/racingcar/src/main/java/utils/View.java @@ -1,6 +1,7 @@ package utils; import domain.Car; +import domain.Cars; import java.util.List; import java.util.stream.Collectors; @@ -32,9 +33,13 @@ public static void resultView(final List cars){ System.out.println(winner); } - public static void carStatusView(Car car) { - View.carNameView(car.getName()); - View.distanceView(car.getPosition()); + public static void carStatusView(Cars cars) { + cars.getCars() + .stream() + .forEach(car -> { + View.carNameView(car.getName()); + View.distanceView(car.getPosition()); + }); } public static void spacingWord() { From 246a36d4d641fcdaadb217a415996494e60aa81c Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Thu, 6 May 2021 10:35:19 +0900 Subject: [PATCH 16/18] =?UTF-8?q?refactor:=20View=EB=AA=85=EC=B9=AD=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/service/RacingGame.java | 8 ++++---- .../java/utils/{View.java => RacingGameStatusView.java} | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) rename 8week/racingcar/src/main/java/utils/{View.java => RacingGameStatusView.java} (83%) diff --git a/8week/racingcar/src/main/java/service/RacingGame.java b/8week/racingcar/src/main/java/service/RacingGame.java index e43c5d79..ba90d4ec 100644 --- a/8week/racingcar/src/main/java/service/RacingGame.java +++ b/8week/racingcar/src/main/java/service/RacingGame.java @@ -2,7 +2,7 @@ import domain.Cars; import domain.Number; -import utils.View; +import utils.RacingGameStatusView; public class RacingGame { @@ -14,9 +14,9 @@ public static void start() { int times = count.getCount(); while (times-- > 0) { cars.moveCars(); - View.carStatusView(cars); - View.spacingWord(); + RacingGameStatusView.carStatusView(cars); + RacingGameStatusView.spacingWord(); } - View.resultView(cars.getWinner()); + RacingGameStatusView.resultView(cars.getWinner()); } } diff --git a/8week/racingcar/src/main/java/utils/View.java b/8week/racingcar/src/main/java/utils/RacingGameStatusView.java similarity index 83% rename from 8week/racingcar/src/main/java/utils/View.java rename to 8week/racingcar/src/main/java/utils/RacingGameStatusView.java index 8fa461ff..22946624 100644 --- a/8week/racingcar/src/main/java/utils/View.java +++ b/8week/racingcar/src/main/java/utils/RacingGameStatusView.java @@ -6,13 +6,13 @@ import java.util.List; import java.util.stream.Collectors; -public class View { +public class RacingGameStatusView { private static final String FINAL_WINNER = "최종 우승자 : "; private static final String COLON = " : "; private static final String COMMA = ", "; private static final String POSITION_VIEW = "-"; - private View() {}; + private RacingGameStatusView() {}; public static void distanceView(int position) { while (position-- > 0){ @@ -37,8 +37,8 @@ public static void carStatusView(Cars cars) { cars.getCars() .stream() .forEach(car -> { - View.carNameView(car.getName()); - View.distanceView(car.getPosition()); + RacingGameStatusView.carNameView(car.getName()); + RacingGameStatusView.distanceView(car.getPosition()); }); } From cd85a5d8874d5cf740252918d0c9c1febd39ccd8 Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Thu, 6 May 2021 10:42:49 +0900 Subject: [PATCH 17/18] =?UTF-8?q?refactor:equals=20null=20=EC=98=88?= =?UTF-8?q?=EC=99=B8=20=EC=B2=98=EB=A6=AC=20=EA=B0=80=EB=8A=A5=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/domain/Car.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8week/racingcar/src/main/java/domain/Car.java b/8week/racingcar/src/main/java/domain/Car.java index aabe200d..06def772 100644 --- a/8week/racingcar/src/main/java/domain/Car.java +++ b/8week/racingcar/src/main/java/domain/Car.java @@ -38,7 +38,7 @@ public String getName() { } private void validateInput(String buffer) { - if (buffer.contains(" ")) { + if (" ".equals(buffer)) { throw new IllegalArgumentException("[ERROR] 잘못된 입력입니다."); } } From 8f12ba76cb818c71844e618d32ba989d3de5a3fe Mon Sep 17 00:00:00 2001 From: DongLee99 Date: Thu, 6 May 2021 11:10:08 +0900 Subject: [PATCH 18/18] =?UTF-8?q?refactor:Cars=EC=9D=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=B2=B4=ED=81=AC=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 8week/racingcar/src/main/java/domain/Cars.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/8week/racingcar/src/main/java/domain/Cars.java b/8week/racingcar/src/main/java/domain/Cars.java index c9760b92..bb38e583 100644 --- a/8week/racingcar/src/main/java/domain/Cars.java +++ b/8week/racingcar/src/main/java/domain/Cars.java @@ -35,10 +35,10 @@ public void moveCars() { } private void validateCars(List carNames) { - Boolean value = (int) carNames.stream() + Boolean distinctCheck = (int) carNames.stream() .distinct() .count() != carNames.size(); - if (value) { + if (distinctCheck) { throw new IllegalArgumentException("[ERROR] 이름 중복"); } }