login register Sysop! about ME  
qrcode
    최초 작성일 :    1999년 02월 23일
  최종 수정일 :    2001년 07월 17일
  작성자 :    taeyo
  편집자 :    Taeyo (김 태영)
  읽음수 :    601,855

강좌 목록으로 돌아가기

필자의 잡담~

..

Application Object & Global.asa

Application 개체는 상당히 개념적입니다. 그래서 어렵게 느껴질 수 있지만 반드시 그 개념과 동작하는 것을 기억해야만 하는 중요한 개체입니다. 각오하십쇼.

Application이라는 말 자체에서 느껴지듯이 이 개체는 우리의 웹사이트(하나의 어플리케이션) 내를 통째로 지배하게 되는 개체입니다. 기존의 ASP 개체에는 속성과 메소드만이 존재했지만 이 어플리케이션 개체는 이벤트(Event)라는 것이 존재하는데요. 우리가 호출하여 사용할 수 있는 메소드같은 것이 아니라 자동으로 발생하는 사건(?)인 것입니다. Application 개체가 제공하는 이벤트에는  OnStart와 OnEnd가 있습니다.. 그리고, 이에 대한 자세한 이야기는 곧 이어질 것이랍니다.

일단 이 Application 개체를 설명하려면 그 전에 먼저 이야기를 해야하는 특수한 파일이 하나 있는데 그 파일의 이름은 Global.asa입니다. 거창하게 소개를 하면 이 파일은 우리의 웹 사이트(어플리케이션)을 전체적으로 지배하게 되는 파일입니다. 대단한 일을 하는 파일이지만 반드시 존재해야 하는 파일은 아니죠.

우리의 웹 사이트가 동작을 하는 시점과 끝나는 시점에 일어나기 바라는 어떠한 일들이 있다면, 그 일은 이 Global.asa의 파일 내에서 Application 개체의 이벤트를 사용함으로서 가능하게 됩니다.(벌써 어렵나요? 하지만 알고나면 그렇지도 않습니다)

기본적으로 global.asa는 존재하지 않습니다. 단, 인터데브라는 MS툴을 사용하여 사이트를 만들 경우는 기본적으로 이 global.asa를 만들어 주기는 하지요. 여러분도 일단은 이 global.asa 파일을 만들어 여러분의 사이트의 Root에 넣어주시기 바란답니다. 기냥 텍스트 파일을 하나 만드시구요. 그 파일의 이름과 확장자를 단지 global.asa 라고만 지정하시면 됩니다.(아마도 기본적으로라면 C:\inetpub\wwwroot 가 그 위치가 되겠네요)

파일안에는 뭐라고 내용을 넣냐구요? 아무것도 넣을 필요가 없습니다. 일단은요

아무 처리도 안 한 global.asa라면 여러분의 사이트에 그 어떤 문제도 일으키지 않을 것입니다. 그렇다면 어떤 처리를 한 global.asa는 어떤 영향을 미친다는 것인가요? 그렇습니다. 아마도 여러분은 천재가 아닌가 싶네요. 하나를 알려주면 열을 아시는군요. 오오~~

기본적인 global.asa의 모습은 4개의 이벤트로 구성되어져 있습니다. 그렇다면 global.asa 란 무엇인가? 왜 필요한 것인가? 정확히 어디에 쓰이는가? 그것이 궁금합니다. 먼저 Global.asa에 대한 이야기를 들어보도록 합시다...

중요체크!!!   짠짠...  Global.asa에 대하여

global.asa는 상당히 까다로울 작업들을 녀석이 알아서 해결해 주는 착한 녀석입니다. 그 까다로울 작업이란 것은 어플리케이션이 시작되고 끝나는 시점과 세션이 시작되고 끝나는 시점을 체크하는 것이지요. 이 global.asa 가 없다면 어떻게 그러한 시점들을 우리가 체크할 수 있을지 막막하네요. 또한, 이 Global.asa는 우리의 웹 사이트를 들어오는 모든 방문자가 반드시 제일 처음 통과하는 관문입니다.(정확히는 사용자가 우리의 사이트를 방문하여 처음으로 ASP 페이지를 요청하는 순간이지요) 방문자가 우리의 사이트의 그 어떠한 ASP 페이지로라도 ASP 페이지를 첨 접근하는 순간 무조건 이 global.asa를 통과한 후 그 페이지로 자동으로 이동하게 됩니다. 그 누구도 피해갈 수가 없지요.

위의 그림이 그러한 모습을 표현하고 있는데요. 이것은 좀 억지성이 있어보이기는 하지만 이해하기에는 도움이 될 것이라 생각합니다. 사용자가 global.asa 가 존재한 웹 사이트로 입장하면서 처음으로 ASP 페이지를 요청할 경우 이 global.asa가 동작한다는 의미이니까요.. 

그렇다면, 퀴즈~~~!!!

만일, 사용자가 우리 사이트로 입장해서 첫 접근한 페이지가 default.htm 라면.. global.asa는 동작을 할까요? 안 할까요?

오오... 이런 오늘 이 강좌는 보시는 분들은 베리 지니어스 하신 분들뿐인가 봅니다. 그렇습니다. 동작하지 않습니다. global.asa는 ASP 페이지가 처음 요청될 경우에만 동작을 합니다. ^^  호호... 대단들 하시군요.. 저도 대단하죠? 아부하는 수준이 말입니다..히힛

다시 원래의 이야기로 돌아와서 이 global.asa는 그 기능들을 제공해 줍니다. 우리는 그 제공되는 시점에서 해야할 일들을 코딩해주기만 하면 되는 것이지요. Global.asa 에는 4개의 주요이벤트를 감지하는 책임이 있습니다. 그 4개의 이벤트라함은 Application_OnStart 과 Application_OnEnd 그리고 Session_OnStart 와 Session_OnEnd 입니다.우선 global.asa의 기본 소스를 보시겠습니다.


<SCRIPT language=VBScript RUNAT="Server">

Sub Application_OnStart
'어플리케이션이 시작할 때의 해야할 일을 코딩
End Sub

Sub Application_OnEnd
'어플리케이션이 끝날 때 해야할 일을 코딩
End sub

Sub Session_OnStart
'사용자마다 각각의 세션이 시작할 때의 해야할 일을 코딩
End Sub

Sub Session_OnEnd
'사용자마다 각각의 세션이 끝날 때의 해야할 일을 코딩
End Sub

</SCRIPT>

Global.asa 는 <SCRIPT language=VBscript RUNAT="Server"> 라는스크립트로 시작해서 </SCRIPT> 로 끝나게됩니다. 이 안에다가 4개의 이벤트를 코딩하면 되는 것이지요. "Runat= Server"라 함은 이 스크립트는 서버에서 실행된다는 의미이다. ASP를 작성할 때 쓰는 <% %> 와 기능면에서 같다고 볼 수 있습니다만 위의 스크립트표시 대신에 <% %>를 사용하면 에러가 납니다. 주의하세요....

그럼 그 시점이라는 것이 언제냐? 그걸 알아야지만 알맞게 코딩을 넣을 수 있을 것이죠? 그렇죠?

먼저 Application_OnStart, 이것은 첫 사용자가 홈(내지는 가상) 디렉토리로에 최초로 웹 페이지(ASP페이지)를 요청했을 때 오로지 한 번만 발생하는 것으로, 서버가 스타트하기 시작하고 첫 사용자가 들어오면 그때 한 번 실행되고 다시는 실행되지 않습니다.

그 이후부터는 Session_OnStart 라는 녀석이 실행되게 되지요. 매 사용자가 들어올 때마다 이 Session_OnStart를 거치게 되는데, 이는 누구나 반드시 거칠 수밖에 없는 이벤트입니다. 세션이라는 것은 각각의 사용자의 연결자체를 의미한다고 보시면 됩니다. 기본적으로 세션은 20분간 지속되며, 사용자가 빠져나간지 20분이 지나면 Session_OnEnd가 실행되어 집니다. 그리고 가상 디렉토리에서 모든 사용자의 세션이 끝나게 되면 그때 Application_OnEnd가 실행되게 되는 것이지요. 허허.. 어렵나요? 어려웁게 들려야 정상입니다...  ^^

이해를 돕기 위해 예를 들어보도록 하겠다. 우리의 사이트가 이제 막 오픈을 시작했습니다. 그리고 얼마 지나지 않아 첫번째 방문자 A가 우리의 사이트를 들어오고(그 방문자는 우리 자신일 수도 있겠죠?), 그 순간 global.asa의 application_OnStart는 작동을 시작합니다. 그리고, Session_OnStart도 시작합니다.

첫번째 사용자 A가 들어온 후 5분이 지난 시점에 두번째 방문자가 들어왔다고 가정합니다. 이때 이 사용자에게도 Session_OnStart가 동작하게 됩니다. Session_OnStart 이벤트는 각각의 사용자에게 각각 적용되는 이벤트이기 때문이지요. 현재 우리의 사이트에는 2명의 사용자가 활동중인데, 시간이 흐른 뒤 첫번째 사용자가 우리의 사이트에서 즐거운 서핑을 마치고 나갔을 경우, 대부분 첫번째 사용자의 Session_OnEnd가 발생할 것으로 기대하지만 안타깝게도 그렇지는 않습니다.

Session_OnEnd 이벤트는 그 사용자의 세션이 끝나는 시점에서 발생하지, 그 사람이 우리의 사이트를 빠져나가는 시점에서 발생하는 것이 아닙니다. 서버는 사용자가 우리 사이트를 빠져나갔는지 아닌지 알 수가 없습니다. 서버가 각각의 사용자의 집을 쳐다보고 있다가... 그 사용자가 우리 사이트를 빠져나갔는지 아닌지를 지켜볼 수는 없는 노릇이잖아요? 사용자가 브라우저를 닫았는지, 사용자가 다른 사이트로 이동을 했는지 알길이 없습니다.

이것은 우리의 경우도 마찬가지입니다. 여러분의 친구와 통화를 하고 있다고 생각해 보세요.. 그 친구보구 "야야.. 이 사이트 죽인다 한번 들어가봐.. 지금" 이라고 했어요.. 그랬더니 친구는 "그래..지금 들어간다" 라고 말하죠...

그래서 내가 "들어갔냐. 메인에 서태지 사진 보이냐?" 라고 이야기 합니다. 그랬더니 친구는 "보인다"라고 이야기 하죠....여기까지는 좋습니다.. 내가 계속 서태지 이야기를 했더니만 친구는 조금 지루하기 시작했나 봅니다. 그러나, 지칠줄 모르고 저는 계속 이야기를 하죠...

"야야.. 그 사진을 누르고 본문으로 들어가봐. 재미있는 글이 있어".. 친구는 "응"하고 조용한 반응입니다. 내가 "재미있지?" 하니깐 친구는 "응" 이라고 말합니다.. 이런 "응"은 대부분 성의없는 "응"이라고들 부르지요.. 분쟁을 일으킬 수 있는 "응"이란 판단이 사정없이 들면서 의심스럽습니다.

"이 넘이 정말로 본문을 읽기는 한 걸까? 정말 본문 페이지로 들어가기는 했을까? 다른 사이트에서 만화를 보면서 건성으로 대답하는 것은 아닐까?" 해서 물어봅니다..."야야.. 너 지금 그 사이트에 있는거 맞어?" 대답해... 하지만, 더 이상 대답없는 친구....  과연 그 사이트에 남아있는 것인가? 아닌가?

비유가 어설프기는 했지만, 우리도 친구가 사이트에서 나갔는지 아닌지를 알 방법은 없습니다. 그 친구의 말을 해주지 않는다면요.. 하지만, 그 친구 거짓말을 했을 가능성이 크지요? 그래도 우리는 서버입장보다는 나은 것입니다.

서버는 사용자가 어떤 액션을 주지 않으면 하나도 제대로 판단할 수 있는 것이 없습니다.  ^^ 즉, 서버는 사용자가 어떤 페이지를 요청하게 되면 그 때, 이렇게 생각합니다. "아아.. 이 사용자는 지금 내 사이트에 들어와 있구나.." 라구요...

그리고, 시간이 흐릅니다.. 10분이 지나서 아까 그 사용자가 또 다른 페이지를 요청합니다. 그러면 서버는 이렇게 생각하지요 "아아.. 이 친구 아직도 있구나"

하지만, 1시간이 지나면? 2시간이 지나면? 아니면 그 친구가 브라우저를 닫고 내 사이트를 나갔다면? 여기서 주의할 것중에 하나는 인터넷이라는 특이한 연결입니다. 여러분이 태오 사이트를 보고 있는 지금 이 순간 여러분은 태오 사이트에 들어와있다고들 이야기하지만 사실은 그렇지 않습니다. 여러분은 태오사이트에 들어오고 나가고를 무지하게 반복하고 있는 겁니다.

여러분이 태오 사이트에 들어오는 시간은 지금 이 페이지를 로딩하는 그 몇초의 시간뿐 입니다. 페이지의 로딩이 완료되면 여러분의 브라우저와 서버와의 연결은 끊어집니다. 이 페이지의 로딩이 끝났고 여러분은 이 글을 읽고 계시죠? 그렇다면, 랜선을 뽑아버리거나 모뎀을 꺼버려보세요,. 그렇다고 이 페이지가 사라지나요? 그런 것은 아니죠? 여러분은 태오 사이트에서 여러분이 필요한 문서를 다운로드 받은 것이고 지금 이 순간 여러분은 인터넷의 연결없이 단지 여러분 로컬  하드에 다운로드된 HTML을 보고 있는 것입니다.

서버가 여러분을 인식하는 순간은 여러분이 페이지를 요청한 그 몇초 혹은 그보다도 안되는 찰라의 순간입니다.  ^^

해서, 서버는 각각의 사용자들이 입장하는 시점을 알 수가 있지만..(처음 페이지를 요청하는 시점이 바로 입장하는 시점이잖아요?) 나가는 시점은 알수가 없는 것이지ㅛ..

그렇다면, 그 사람이 우리의 사이트를 빠져나갔는지 체크할 방법이 전혀 없을까요? .

그래서 하나의 해결 방안으로, 사용자가 기본적으로 20분간 우리의 사이트에서 그 어떠한 액션도 하지 않으면 사이트를 빠져나갔다고 생각하고 그제서야 세션이 끊어지도록 하는 것이랍니다. 어떤 페이지를 요청한 뒤에 20분동안 다른 페이지의 요청이 없으면 서버는 "아아.. 그넘이 나간 것이야.. 내가 관심법으로 보았지"라고 한다는 것입니다. 즉, 첫번째 사용자의 Session_OnEnd를 동작한다는 것입니다.

곧 이어 두번째 사용자도 우리의 사이트를 떠난다고 가정합시다. 그 사람의 세션도 그 사람이 우리의 사이트를 떠난지 20분이 지나야 끊어집니다. 시간이 흘러 20분이 지났습니다. 이제 두번째 사용자의 세션도 끊어진다. 즉, Session_OnEnd가 동작하겠죠? 마지막 남아있던 세션이 끝나면 그때 Application_OnEnd는 작동한다고 말씀드렸습니다. 이해가 되나요?

더욱 이해를 용이하게 하고자 아래의 그림을 준비했슴다. 게다가 더욱 도움이 되고자 시간까지 표시했답니다.

자.. 그림과 함께 보아나갑시다...


Q> 우리의 웹 서버는 12:00 조금 전에 서비스를 시작했다고 가정했을 때,
12:00 사용자 A 사이트에 접속을 시도합니다. 이때 무슨 이벤트가 발생할까요?

A> Application_OnStart, Session_OnStart 가 발생합니다. 이 사용자는 우리 사이트가 서비스를 시작한 뒤 첨 들어오는 사용자이기에, 첫 문을 여는 사용자이기에 Application_OnStart를 일으키게 되는 것이지요.. 그리고, 자신의 Session_OnStart 도 발생시키겠지요?

Q> 12:05 두번째 사용자 B가 들어옵니다. 이 사용자는 어떤 이벤트를 발생시킬까요?

A> Session_OnStart 입니다. Application_OnStart는 이미 A 가 시작시켰으니깐 다시 시작시킬 필요가 없습니다.

Q> 14:00 첫번째 사용자였던 A 가 사이트를 나갑니다. 이 시간에 사용자는 어떤 이벤트를 발생시킬까요?

A> 아무 이벤트도 일어나지 않습니다. 사용자는 나갔지만 서버는 아직 이 사용자가 나갔다는 사실을 모릅니다. 사용자 A의 Sessin_OnEnd는 14:20 분에 일어나게 되는 것이지요

Q> 14:30 첫번째 사용자였던 B 가 사이트를 나갑니다. 이 시간에 사용자는 어떤 이벤트를 발생시킬까요?

A> 역시 아무 이벤트도 일어나지 않습니다. 사용자는 나갔지만 서버는 아직 이 사용자가 나갔다는 사실을 모릅니다. 사용자 B의 Sessin_OnEnd는 14:50 분에 일어나게 되구요. 이 사용자가 우리 사이트의 마지막 사용자이기에 Application_OnEnd도 일어나게 됩니다.

Q> 만일, 두번째 사용자 B가 나간 뒤 19분 59초가 지난 상태에서 이 두번째 사용자가 다시 들어오면 어떻게 될까요?

A> 그렇게 되면 그 두번째 사용자의 세션은 계속 유지되며, 이 사용자는 우리의 사이트에서 빠져나간 적이 없던 것처럼 생각이 되어질 것입니다. 사용자가 페이지 요청후 20분내에만 다시 페이지 요청이 들어오면 서버는 그 사용자는 우리 사이트에 계속 있었다고 가정을 하니까요.. 바보스럽기는 하지만요..  ^^

그리고, 앞으로도 최소한 20분 이상은 세션과 어플리케이션이 종료되지 않을 것입니다. 어플리케이션은 마지막 세션이 끝나는 시점에서 같이 끝나게 되기 때문이지요.

이러한 시점들을 체크해 주는 것이 바로 global.asa로, 그 시점들을 이 global.asa에서 체크해 주기 때문에 우리는 그 필요한 시점의 이벤트 함수에다가 코딩을 해주면 되는 것입니다.

global.asa에 대한 이야기를 듣고나니 이 Application개체가 가진 두 가지 이벤트가 어떤 일을 하는 것인지 다소 이해가 갔을 것입니다. Application개체가 가지는 또 다른 중요한 역할은 우리의 웹 사이트(우리의 웹 어플리케이션)에서 공유할 수 있는 전역변수로서의 역할입니다. 웹 사이트에 전반적으로 걸쳐 사용이 가능한 전역변수를 이 Application 개체를 통해서 만들 수가 있는데 그 방법은 다음과 같아요.

Application("변수이름")

너무나도 간단한가요? 그렇긴 하죠?. 만일 우리가 keyword 라는 이름으로 전역변수를 선언하고 싶고, 그 기본값은 1이라고 지정해 주고 싶다고 한다면 다음과 같이 선언하면 됩니다.

Application("keyword ") = 1

이렇게 선언이 되는 순간부터 이 Application("keyword ") 라는 것은 우리의 웹 사이트 내에서 1이라는 값을 가지게 됩니다. 그 어떤 ASP 페이지에서도 이 변수를 사용할 수가 있는 것이죠. 또한, 공유된 전역변수이기에 어느 ASP 페이지에서나 이 값을 바꿀 수가 있습니다. 한 번 테스트를 해 볼까요?

여러분의 가상 디렉토리나 웹 디렉토리에 다음과 같은 페이지를 하나 만들어 보세요. 아직 내공이 부족하신 분들은 다음 파일을 만들어서 C:\Inetpub\wwwroot 에 넣으시면 될 것입니다.  ^^

Application_1.asp

<% Application("variant") = 1 %>
<HTML>
<HEAD><title>Application 변수 테스트</title>
</HEAD>
<BODY>
<p>현재 Application("variant") 값은 <%=Application("variant")%> 입니다.</p>
<P>그리고, 지금 바로 이 값을 +1 합니다</P>
<% Application("variant") = Application("variant") + 1 %>
</BODY>
</HTML>

그러면 다음과 같은 결과화면이 나오겠지요? 페이지를 확인하기 위해서는 절대로 ASP 페이지를 더블클릭해서 실행하려하면 안되구여.. 일단, 브라우저를 띄우고 다음과 같이 URL을 입력해서 접근해야만 합니다. ASP 페이지는 반드시 그렇게 접근해야만 그를 실행시킬 수 있답니다.

http://localhost/Application_1.asp

localhost 라는 것은 자신서버를 자타내는 것이며, localhost 대신에 서버의 IP주소나, URL, 혹은 컴퓨터 이름을 대신 기입해주어도 문제는 없습니다. 만일, 여러분중에 어떤 분은 MySite 하는 가상 디렉토리를 가지고 있고, 그 디렉토리에 현재의 페이지를 저장했다면 다음처럼 접근해야 하겠죠?

http://localhost/MySite/Application_1.asp

그리고, 현재 이 페이지가 로딩되면서 서버에는 새롭게 Application("variant") 라는 변수가 만들어졌답니다. 그리고, 그 값이 2로 만들어져 있겠지요?

이렇게 Application 변수가 새롭게 만들어지게되면 이 변수는 Application이 종료할 때까지 서버에 존재하게 됩니다. ^^ 한번 만들어지면 말이죠....  그리고, 이 값은 현재의 웹 디렉토리내에서는 모두 공유해서 사용할 수가 있게됩니다. 이것을 확인하기 위해서 같은 디렉토리에 다른 ASP 페이지를 하나 더 만들어 보겠습니다. 자.. 다음과 같은 페이지를 만들어 보세요..  ^^

Application_2.asp

<HTML>
<HEAD><title>Application 변수 테스트</title>
</HEAD>
<BODY>
<p>현재 Application("variant") 값은 <%=Application("variant")%> 입니다.</p>
</BODY>
</HTML>

이 페이지를 실행하면 다음과 같은 결과가 나올 것입니다.

이미 Application_1.asp에 의해서 Application("variant") 값은 2가 되어져 있는 상태이었기에 Application_2.asp 에서는 그 값이 2로 나오는 것을 볼 수가 있지요? 이렇게 Application 변수는 값을 여러 페이지에서 공유해서 읽어올 수도, 저장할 수도 있습니다. 어떤 페이지에서든지간에 그 값을 읽고, 쓸 수 있다는 이야기이지요. ^^

이렇게 Application 변수는 사이트 전역에서 공유해서 사용할 수 있는 변수인 것이랍니다. 하지만, 그러다보니 문제가 하나 생길 수가 있습니다. 어떤 문제일까요?

그것은 동시에 두 사용자가 Application_1.asp 페이지로 접근할 경우에 발생할 수 있는 문제입니다. 만일 동시에 여러명이 Application_1.asp 페이지로 접근하다고 가정해 보세요. 그럴 경우에는 동시에 여러명이 Application("variant") = Application("variant") + 1 를 하려고 할 것이기에..  충돌이 날 수 있습니다..  Application("variant") 값을 동시에 바꾸려고 하니까요..  그럴수 있겠죠?

해서 Application 객체는 두개의 메소드를 또한 제공하고 있는데 그것은...

Lock : Application 개체에 락을 건다. 락을 건 사용자만이 Application 개체를 제어할 수 없다.
Unlock : Application 개체에 걸린 락을 풀어준다. 모든 이들이 다시 Application 개체에 접근이 가능하다

입니다.  ^^

해서, Application_1.asp 페이지처럼 Application 변수를 바꾸거나, 지정하는 코드의 앞뒤에는 다음처럼 락과 언락을 적절히 사용해서 조금이라도 먼저 페이지를 접근한 사람이 먼저 수정을 안전하게 할 수 있도록 하고, 그 사용자가 락을 풀어주면 그 다음 사용자가 다시금 데이터를 수정할 수 있도록 하는 것입니다.

Application.lock
Application("variant") = Application("variant") + 1
Application.unlock

락에 대한 이야기로 Application 에 대한 강좌도 정리할 시간이 온 것 같습니다. 이번 강좌는 이전 강좌에 비하면 그리 길지 않았지만 나름대로 중요한 이야기들을 나눈 것 같습니다. 사이트를 프로그래밍적으로 관리할 경우 이 Application 개체는 상당히 중요한 역할을 하기에 반드시 개념적으로 이해하고 있어야만 합니다. ^^ 꼭요..

그럼 수고하셨구요...  다음 표로 Application 객체의 메소드와 이벤트를 정리하고 이번 강좌를 마쳐보겠습니다. 감사합니다.

메소드 설명
Lock Application 개체에 락을 걸어 다른 사용자가 접근하지 못하게 한다.
락을 건 사용자만이 개체를 조절할 수 있다.
UnLock Application 개체에서 락을 해제한다
이벤트

설명

OnStart 웹사이트의 어플리케이션이 시작할 때 발생
OnEnd 웹사이트의 어플리케이션이 종료할 때 발생

authored by


 
 
.NET과 Java 동영상 기반의 교육사이트

로딩 중입니다...

서버 프레임워크 지원 : NeoDEEX
based on ASP.NET 3.5
Creative Commons License
{5}
{2} 읽음   :{3} ({4})