■ src/main/java





■ src/main/webapp





■ DAO Package - 데이터베이스와 연결, 쿼리문 실행, 해제를 담당할 객체





■ ServicePakage - DAO를 활용하는 객체






■ VO Package - 데이터베이스에 있는 데이터를 저장할 객체






■ Web Package - 클라이언트의 요청을 받고 다시 응답을 해주는 객체





■ filter Package - web.xml과 서블릿 중간에서 공통적으로 작업해주는 객체





■ util Package - 데이터베이스 연동하는 코드를 재활용 목적으로 만든 객체




■ lib 폴더 - 필요한 라이브러리 모음





■ view 폴더 - 클라이언트에게 보여줄 JSP파일




■ web.xml - 클라이언트 요청에 맞는 서블릿을 찾아주는 파일





















'Web' 카테고리의 다른 글

게시글 만들기 - 데이터 베이스  (0) 2018.08.17
jstl.jar파일 standard.jar파일 빌드하기  (0) 2018.08.17
데이터베이스 연동  (0) 2018.08.16

■ 클라이언트 요청

클라이언트가 웹브라우저에 url을 입력한다. 

localhost:8080 - 연결할 파일이 있는 서버를 가리킨다. 8080은 포트번호로서 htttp 프로토콜 번호 8080을 의미한다.

board - 서버에 연결되면 연결할 파일이 들어있는 폴더명을 입력받게 된다. 


■ Servlet


서블릿은 Servlet Container 위에서 동작되는 자바 프로그램이다. 본인은 서블릿 컨테이너로 톰캣을 사용하였다.

클라이언트 요청을 웹서버가 인지하기 위한 정보들이 필요한데 이러한 정보들이 XML파일에 기록되어 있다.


■ web.xml




display-name을 보면 board라고 적혀있다. 클라이언트 요청한 파일이 저장되어있는 폴더 명이다.

web.xml 파일에는 서블릿과 JSP를 어떻게 실행하여야 하는지가 적혀있다. 이러한 역할을 DD(Deployment Descriptor)라고 한다.

내용들을 살펴보니 <servlet-mappling> 태그 안에 BoardListServlet이라는 서블릿 클래스를 "/"로 매핑이 되어 있음을 알 수 있다.







서블릿 클래스 즉 BoardListServlet는 <servlet>태그 안에 정의가 되어있다.

그 내용을 살펴보니 서블릿 클래스의 경로가 com.ktds.board.web.BoardListServlet 에 있음을 알 수 있다.

지정되어 있는 서블릿 클래스를 실행하게 된다.



■ 서블릿 클래스





xml 파일에 정의된 서브클래스를 살펴 보겠다.

해당 서블릿 클래스는 기본적으로 자바 클래스 생성된 것을 알 수 있다. 그리고 HttpServlet 클래스를 상속받고 있다.

부모 클래스를 상속 받고있는 하위 클래스는 doGet 메소드와 doPost메소드를 갖고 있다.

이 두 가지의 메소드는 전달 방식을 의미하며 get은 가져오는 개념이고 post는 수행하는 개념이다.


get방식은 주소창에 값이 출력된다. 그리하여 작은 데이터를 처리할 때는 get방식이 용이하다. 

사용자가 요청하는 데이터를 보여주기 위해서 주로 사용된다. 


반면에 post 방식은 주소창에 값이 출력되지 않는다. 많은 양의 데이터를 보낼 때는 주로 post방식을 사용하게 되는데 주로 게시판에 글을 작성하게 되면 글의 내용이 DB에 저장이 되고 수정을 하면 DB에 저장된 값이 수정된다. 이때 주로 Post 방식을 사용한다. 


화면창에 값을 출력하기 위해서 get 방식을 사용하겠다. doGet 메소드의 아규먼트를 살펴보니 두 개의 객체가 보인다. request는 클라이언트의 요청을 처리하기 위한 객체이며 response는 클라이언트의 응답을 처리하기 위한 객체이다.


◆ 서블릿의 생명주기


1. 객체생성 -  톰캣과 같은 WAS가 자바파일을 컴파일하여 클래스 파일을 만든 다음 메모리에 할당하게 된다. 서블릿 클래스를 메모리에 

할당하여 객체를 생성한다. 이후부터 서블릿 객체는 다시 생성되지 않으며 메모리에 할당된 서블릿 객체만을 사용하게 된다.

2. init() - 객체가 생성되었다면, init() 메소드가 호출되어 초기화 작업을 수행한다.

3. Service() - 서비스 메소드는 클라이언트의 요청에 따라서 get방식과 post방식을 사용하게 된다. 여러명의 클라이언트의 작업을 동시에 작업하기 위하여 쓰레드가 생성이 되고 작업을 병렬로 처리할 수 있게 된다.   

4. destory() - 서블릿의 사용이 끝나게 된다면, destroy()메소드 호출되어 연결을 해제한다.



■  Service 호출



서비스를 호출하는 문이다.



BoardService의 인터페이스다. 기능을 정의하는 부분이고 기능을 구현하는 부분은 BoardServiceImpl 클래스에 있다.





BoardServiceImpl 클래스 안에 BoardDAO 클래스가 선언되어 있다.





인터페이스의 구현 클래스 BoardServiceImpl의 readAllBoard 메소드를 보니깐 리턴타입이 List<BoardVO> 이며


boardDAO 클래스에 있는 selectAllBoards 메소드를 반환한다.




BoardDAO객체는 데이터베이스와 연동하는 객체로서 그 의미가 있다. 이것 또한 인터페이스이며 기능만 정의되어 있다.

기능이 구현되어있는 BoardDAOImpl를 확인해보겠다.






BoardDAOImpl 클래스에는 오라클에 접속하고 쿼리문을 실행 준비하고 쿼리문을 실행하는 역할을 담당한다



■ 오라클 접속





계속해서 쓰이는 부분이기 때문에 메소드로 만들었다.



필요한 부분에서 이렇게 오라클을 접속하는 메소드를 호출하였다.



■오라클 계정을 로그인 하기




데이터 베이스 계정으로 로그인하는 부분이다.

이 부분도 자주 쓰이기 때문에 재활용의 목적으로 메소드로 구현하였다.




Connection conn = createDatabaseConnection();

를 통하여 데이터 베이스에 접속하였다.




■ 쿼리문 준비





쿼리문은 항상 달라지기 때문에 쿼리문을 준비하는 부분은 추상메소드로 정의하였다





이렇게 선언을 했으면 구현하는 부분은 BoardDAOImpl 클래스에 구현이 되어있다.








Sql 클래스를 선언한 다음 추상메소드로 선언된 쿼리문 준비 부분만 이렇게 구현하면 된다




■ 쿼리문 실행




Sql 클래스에 선언된 추상 메소드이다.









BoardDAOImpl 클래스에서 쿼리문을 실행하는 부분을 구현시킨다.








마지막으로 리스트객체로 반환한다.



■ 데이터베이스 연결 해제





데이터베이스 연결을 하제하는 것은 ResultSet > PreparedStatement > Connection 순서대로 기존의 선언된 역순으로 해제하면 된다.

이 부분 또한 자주 사용 되는 부분이기 때문에 따로 메소드로 구현하였다.






필요한 부분에 이렇게 메소드를 호출하면 된다.



■ 클라이언트 요청 응답




RequestDispatcher가 클라이언트에게 JSP를 보여주는 역할을 담당하다. 

path 즉 경로를 확인해보니깐 list. jsp 파일이 있다고 정의 되어있다.




RequestDispatcher가 forward 메소드를 통하여 브라우저에 보여주게 된다.

























'Web' 카테고리의 다른 글

게시글 만들기 - 데이터 베이스  (0) 2018.08.17
jstl.jar파일 standard.jar파일 빌드하기  (0) 2018.08.17
게시글 만들기 - 구성  (0) 2018.08.17


■ 오라클 홈페이지


























■ 환경설정





JDK 파일 경로를 복사한다.


























복사하였던 파일 경로를 붙여넣기 한다.















Path를 지정해야한다. Path 를 선택한 다음 편집을 눌러준다.









변수값 가장 끝에 ;%JAVA_HOME%\bin; 을 입력하고 확인을 누른다. 



■ 환경변수 설치 확인








명령어를 입력했을 때 잘 나온다면 설정을 잘 마무리 한 것이다.






'JAVA' 카테고리의 다른 글

변수 & 변수의 종류 & 변수의 자료형  (0) 2018.08.02
자바의 동작원리  (0) 2018.08.02

■ 면담 수행하기


조직이 어떻게 데이터를 수집하고 어떻게 표현해야하는지 면담을 통해 요구사항들을 파악해야 한다.

관리자는 검토를 통해 샘플에 관한 구체적인 질문이 필요하고 사용자는 명확한 답변이 필요하다. 사용자와 관리자의 면담으로 통해 얻어진 결과는 초기 데이터베이스를 위한 초기 필드와 테이블 구조를 식별하는데 도움이 된다. 면담은 담으과 같은 초점을 맞춘다.

사용자들이 현재 사용하고 있는 데이터의 종류

사용자들이 현재 그들의 데이터를 사용하는 방법

분석의 처음 두 단계에서 모은 샘플들

사용자들이 일상적인 작업을 위해 필요로 하는 정보의 종류


관리자는 사용자에게 추상적인 답변을 받았을 때는 심층 질문을 통해 구체적인 답변을 반드시 요구해야 한다. 예를 이러한 질문들이 있을 것이다.

1. 고객을 정의해 주세요. 고객들은 어떤 정보를 가지고 있나요? 아이디, 비번, 주소, 생년월일 등등

2. 상품을 정의해 주세요. 상품은 어떤 정보를 가지고 있나요? 사진, 상품가격, 할인율, 할인된 금액, 제고, 품절 여부, 원산지 등등

3. 카테고리를 정의해 주세요. 가전 > 생활가전 > 노트북 >  부품  등등


컬럼의 정보만으로 계산을 할 수 있다면 컬럼에 넣지 않는다. 예를 들어 합계 같은 경우에는 내부에서 데이터를 가공하여 얻을 수 있는 결과이기 때문에 따로 컬럼을 만들 필요가 없다는 말이다. 만약에 외부로부터 오는 데이터 예를 들면 마일리지 같은 경우에는 컬럼이 경우 따라서 필요할 것이다. 


■ 완전한 필드 목록 수집하기


1. 특성 목록을 검토하고 정제한다.

1) 같은 이름을 가진 항목들 제거한다.

2) 같은 특성을 나타내는 항목들 정제한다.

3) 항목들이 특성들을 나타내는지 확인하기


2. 샘플에 새로운 특성들이 있는지 파악한다



■ 테이블 관계

충분한 요구사항 단계를 통해 테이블 관계를 설계해야 한다. 



참고: 운명적 존재를 위한 데이터베이스

'Database > SQL' 카테고리의 다른 글

HR 계정 SQL 50문제  (0) 2018.08.17
SQL 50문제 실습하기  (0) 2018.08.17
SQL 서브쿼리  (0) 2018.08.03

■ 서브쿼리란?


서브쿼리는 쿼리 안에 있는 쿼리문이다. 쿼리란 SELECT문을 참조할 때 사용한다. SELECT문이란 테이블에서 정보를 가져오기 위해 사용한다.

요약을 하자면, 테이블에서 정보를 가져오기 위해 SELCT문을 사용해서 또 다른 SELECT문을 참조한다고 풀이할 수 있다.


-- ALLEN의 직무와 같은 사람의 이름, 부서명, 급여, 직무를 출력하라.


-- JONES 가 속해있는 부서의 모든 사람의 사원번호, 이름, 입사일, 급여를 출력하라.


-- 전체 사원의 평균 임금보다 많은 사원의 사원번호, 이름, 부서명, 입사일, 지역, 급여를 출력하라.


공통점은 어떤 결과와 컬럼을 비교하기 위해 사용한다. 이러한 문제들은 서브쿼리문을 사용하지 않으면 문제를 해결 할 수 없다.



■ 서브쿼리 프로세스


-- FIRST_NAME이 STEVEN인 사원과 같은 부서에서 일을 하는 모든 사원들의 정보


이러한 문제가 있다고 가정을 해보자. 그럼 우선 아래와 같은 과정을 통해 문제를 해결하면 도움이 될 것이다.


1. 어떤 정보를 보고싶은가?

2. 정보가 어디 테이블에 있는가?

3. 조건은 무엇인가? 


우리는 모든 사원들의 정보를 보고싶다. 그 다음 이러한 정보가 어디 테이블에 있는지 알아보니 EMPLOYEES라는 테이블에 있다. 마지막으로 이름이 Steven이라는 사원과 같은 부서에 근무해야 하는 조건에 만족해야 한다.


<Steven이라는 사원과 같은 부서를 조회할 때 문제직면>

1
2
3
4
5
6
SELECT   *
 
FROM     EMPLOYEES
 
WHERE    DEPARTMENT_ID = ?????
;
cs



Steven과 같은 사람의 부서를 비교를 해야하는데 서브쿼리를 모른다면 문제를 해결 할 수 없다. 그렇다면 Steven의 부서를 출력하는 문을 적어보자


<Steven이라는 사람의 부서번호 출력하는 SELECT문>

1
2
3
4
5
6
SELECT    DEPARTMENT_ID
 
FROM      EMPLOYEES
 
WHERE     FIRST_NAME = 'Steven'
;
cs


<출력결과>

출력결과 보니깐 두개가 나왔다. 그렇다면 동명인이 존재하는 것이다. 이런 상황에서 서브쿼리를 사용해보자. ???? 된 곳에 괄호를 쳐서 Steven의 부서를 출력하는 SELECT문을 넣으면 서브쿼리가 완성된다.


<서브 쿼리문>

1
2
3
4
5
6
7
8
SELECT  *
FROM    EMPLOYEES
WHERE   DEPARTMENT_ID = (
                            SELECT  DEPARTMENT_ID
                            FROM    EMPLOYEES
                            WHERE   FIRST_NAME = 'Steven'
                        )
;
cs

<출력문>


에러문이 나왔다. 그 이유는 동명인이 존재하기 때문이다. 서브쿼리문 안에는 출력결과는 2개가 나오는데 어떤 Steven을 말하는지 모르겠다. 라고 말하는 것이다.

<FIRST_NAME이 STEVEN인 사원과 같은 부서에서 일을 하는 모든 사원들의 정보 서브쿼리>

1
2
3
4
5
6
7
8
9
SELECT  *
FROM    EMPLOYEES
WHERE   DEPARTMENT_ID IN (
                            SELECT  DEPARTMENT_ID
                            FROM    EMPLOYEES
                            WHERE   FIRST_NAME = 'Steven'
                        )
;
 
cs

'='은 한 개의 데이터와 비교 할 때 쓰이기 때문에 'IN'을 사용하면 여러 개의 데이터와 비교할 수 있어서 문제를 해결 할 수 있다.

추가적으로 서브쿼리문에서는 공백을 사용하면 안된다. 주의하자.


그렇다면 위에 문제를 응용해서 Steven은 제외한다 라는 조건이 더 붙으면 어떻게 작성해야 할까?


<Steven은 제외한다 라는 조건이 추가>

1
2
3
4
5
6
7
8
9
SELECT  *
FROM    EMPLOYEES
WHERE   DEPARTMENT_ID IN (
                            SELECT  DEPARTMENT_ID
                            FROM    EMPLOYEES
                            WHERE   FIRST_NAME = 'Steven'
                        )
AND     FIRST_NAME !='Steven'
;
cs



◆ IN vs '='


<IN 사용>

1
2
3
4
5
SELECT  *
 
FROM    EMPLOYEES
WHERE   DEPARTMENT_ID IN (1020)
;
cs

<'=' 사용>

1
2
3
4
5
6
SELECT  *
FROM    EMPLOYEES
WHERE   DEPARTMENT_ID = 10
OR        DEPARTMENT_ID = 20
;
 
cs

두 SELECT문은 같은 결과를 출력하지만 속도측면에서 '='를 쓴 SELECT문이 더 빠르다. 상황에 맞게 사용하면 될 것이다.
IN과 '=' 차이점은 간단하다. '='는 한 개의 데이터와 비교하는 할 때 쓰인다. IN을 사용할 때는 1개 이상 데이터와 비교할 때 사용한다.
하지만, 속도 측면에서 IN은 상대적으로 비효율적이기 때문에 1개 데이터를 비교할 때는 꼭 '='을 사용하자. 



◆ JOIN문만 사용 VS 서브쿼리만 사용 VS JOIN문 서브쿼리 사용

HR계정에서 "Seattle"에서 근무하는 모든 사원들을 조회하라" 라는 문제를 풀어보자

1. JOIN문만 사용해서 풀어보기

1
2
3
4
5
6
7
8
9
SELECT  *
FROM    EMPLOYEES EM
        , DEPARTMENTS DE
        , LOCATIONS LO
WHERE   EM.DEPARTMENT_ID = DE.DEPARTMENT_ID
AND     DE.LOCATION_ID = LO.LOCATION_ID
AND     LO.CITY = 'Seattle'
;
 
cs

2. 서브쿼리만 사용해서 풀어보기

1
2
3
4
5
6
7
8
9
10
11
12
SELECT  *
FROM    EMPLOYEES EM
WHERE   EM.DEPARTMENT_ID IN (
                                SELECT  DE.DEPARTMENT_ID
                                FROM    DEPARTMENTS DE
                                WHERE   DE.LOCATION_ID = (
                                                            SELECT  LO.LOCATION_ID
                                                            FROM    LOCATIONS LO
                                                            WHERE   LO.CITY = 'Seattle'
                                                         )
                           );
 
cs


3. JOIN문과 서브쿼리를 사용해서 풀어보기

SELECT  *
FROM    EMPLOYEES EM
        , DEPARTMENTS DE
WHERE   EM.DEPARTMENT_ID = DE.DEPARTMENT_ID
AND     DE.LOCATION_ID = (
                            SELECT  LOCATION_ID
                            FROM    LOCATIONS
                            WHERE   CITY = 'Seattle'
                         );


'Database > SQL' 카테고리의 다른 글

HR 계정 SQL 50문제  (0) 2018.08.17
SQL 50문제 실습하기  (0) 2018.08.17
데이터베이스 설계  (0) 2018.08.07

변수


변수를 데이터를 저장하는 공간이라고 이해해보자. 예를 들어보겠다


철수는 사과를 10개 가지고 있다.

영희는 배를 5개 가지고 있다.

철수와 영희가 갖고 있는 과일의 개수는 몇 개인가?


이 문장을 자바코드를 사용하여 표현해보겠다.


int apple = 10;

int peach = 5;

int sum = apple + peach;

int totalFruit = sum;


정확히 알수는 없지만 철수와 영희의 상황을 대입해 본다면 직관적으로 이해할 수 있을 것이다. 

apple이라고 하는 메모리에 10을 저장하고 peach라는 메모리에 5를 저장하면 sum이라는 메모리에는 무엇이 들어갈까?

바로 apple의 메모리 주소에 있는 10이라는 데이터와 peach의 메모리 주소에 있는 5라는 데이터를 연산한 데이터가 들어있을 것이다.

마지막으로 totalFruit의 메모리에는 연산한 결과값을 갖고 있는 sum의 데이터가 들어가 있다.


 변수의 종류


1. 사용자에게 입력받는 값

2. 계산을 위해 저장하는 값

3. 계산의 결과 값


위의 상황을 변수의 값으로 대입하면 어떻게 될 것인가?


1. 사용자에게 입력받는 값 - apple 변수, peach 변수

2. 계산을 위해 저장하는 값 - sum 변수

3. 계산의 결과 값 - totalFruit 변수


그렇다면 이러한 변수들을 컴퓨터 즉, 컴파일러에게 알리는 행위가 존재한다. 그것을 선언이라고 한다. 


int apple;


이런식으로 변수를 선언했다고 가정하면 이러한 뜻으로 풀이된다.

"컴파일러야 변수의 이름을 apple이라고 지을게 그리고 int형으로 사용할게 "



int appple = 10;


10이라는 데이터를 할당하는 순간 컴파일러가 apple변수 메모리에 10을 저장하게 된다.

"컴파일러야 사용자에게 입력받은 10이라는 데이터를 저장하는 변수 apple을 int형으로 사용할게 메모리에 할당해줘"



변수의 자료형


그렇다면 int는 무엇인가? 이러한 키워드를 자료형이라고 부른다. 자바에는 자료형이 8개가 존재한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
public class Variables {
 
    public static void main(String args[]) {
        boolean variableBoolean;
        char variableChar;
        byte variableByte;
        short variableShort;
        int variableInt;
        long variableLong;
        float variableFloat;
        double variableDouble;
    }
}
cs


각가 자료형 별로 이름을 붙여줬다. 앞에 variable이라고 변수를 뜻하는 단어를 붙인 이유는 자료형의 이름으로 변수명을 지을 수 없기 때문이다. 이를 예약어라고 한다. 변수명은 예약어로 지을 수 없는 규칙이 있다. 위와 같이 선언을 했으니 값을 저장하게 된다면 컴파일러가 실행 되는 순간 메모리에 데이터들이 할당 받게 된다.


이렇게 8개의 자료형을 primitive type이라고 총칭한다. 각각의 자료형에 맞는 데이터를 저장해야 하기 때문에 어떤 자료형에 어떤 데이터가 들어가야 하는지 숙지해야 할 것이다.



이렇게 사용자가 입력할 수 있는 데이터의 종류는 3가지 존재한다.

1. 숫자

2. 문자

3. true/false

그렇다면, 왜 이렇게 복잡하게 각각의 자료형 마다 값의 범위를 구분하는 것일까?

그것은 메모리 공간의 효율성을 높이기 위해서다. 각각의 자료형마다 차지하는 메모리의 크기는 정해져 있다.

만약에 실수의 데이터 double 같은 경우에는 8바이트의 메모리 크기를 갖고 있다.

작은 숫자를 할당하기 위해서 메모리 크기가 큰 자료형을 사용한다면 메모리 공간의 효율성이 떨어질 것 이다.







'JAVA' 카테고리의 다른 글

자바설치  (0) 2018.08.16
자바의 동작원리  (0) 2018.08.02

■ 시스템을 총괄하는 운영체제


우리가 사용하는 하드웨어들의 기술이 발전하는 속도는 예측하기 어려울 정도로 빠르다. 인간이 할 수 없는 여러가지 일들을 똑똑한 컴퓨터들은 척척 해낸다. 하지만, 우리의 언어를 컴퓨터는 이해할 수 없기 때문에 컴퓨터 언어를 사용하여 컴퓨터에게 명령을 내린다. 이때, 중요한 역할을 담당하는 것이 있다. 그것이 바로 운영체제이다.





우리의 인종은 다양하며 다양한 언어를 사용한다. 언어가 다르면 의사소통을 할 수 없다. 컴퓨터도 마찬가지로 다양한 운영체제가 존재한다. 

운영체제는 하드웨어를 제어하고 컴퓨터 자원을 관리하는 컴퓨터 시스템 총괄자 역할을 한다.  대표적인 운영체제로, Window 운영체제, Linux 운영체제, 맥키토시 운영체제가 있다. 컴퓨터의 명령을 내리기 위해서는 운영체제의 도움이 필요한데 운영체제가 다르면 소통할 수 없다.


 운영체제 통역사 JVM


실제로 운영체제와 대화하는 것은 JAVA언어가 아니다. 바로 JVM이 이러한 역할을 수행한다. JVM은 자바 가상머신이라 불리며, JAVA언어를 어떤 운영체제에서 사용하든지 JVM이 통역 역할을 담당하여 문제없이 프로그램을 실행 시킬 수 있다. 그래서 JAVA 언어의 특징 중에 하나가 이식성이 좋다는 말이 있다. 물론 운영체제 환경에 맞는 JVM를 사용해야 한다. 그래서 오라클 홈페이지에서 JAVA를 다운받을 때 운영체제 맞는 JAVA를 다운받는 것이 이때문이다.


자바의 구동원리는 아래와 같다.

1. 사용자가 작성한 코드로 MyProgram.java라는 소스파일을 만든다. 소스파일은 우리가 이해할 수 있는 언어로 작성된 파일이므로 JVM이 해석 할 수 없다. 그래서 JVM이 해석할 수 있도록 중간 작업을 거쳐야 한다. 

2.  javac.exe라는 실행파일이 자바 컴파일러다. 이는 JVM을 구동시키고, 자바 프로그램이 실행 될 수 있도록 해준다. 컴파일러가 사용자가 작성한 자바 코드를 해석하여 JVM이 해석할 수 있도록 바이트코드로 변환한다. 이렇게 변환된 파일이 MyProgram.class파일이다.

3. 컴파일로 부터 전달받은 클래스 파일을 JVM이 해석하여 우리가 작성한 MyProgram 프로그램을 실행하게 된다.












'JAVA' 카테고리의 다른 글

자바설치  (0) 2018.08.16
변수 & 변수의 종류 & 변수의 자료형  (0) 2018.08.02

+ Recent posts