'programing'에 해당되는 글 25건

  1. 2007.05.07 노드 추가,삭제
  2. 2007.05.05 FireFox에서 removeNode() 메소드를 대체
  3. 2007.05.04 규격
  4. 2007.05.04 실전 웹표준 가이드(2005)
  5. 2007.04.27 JSON
  6. 2007.04.26 레이어이동
  7. 2007.04.17 onbeforeunload
  8. 2007.04.15 트랙백
  9. 2007.04.12 RegExp
  10. 2007.04.10 document.readyState 2

 <SCRIPT LANGUAGE="JavaScript">
  <!--
// // _InsertNodes ff에서사용하기 위함
  if(typeof HTMLElement!="undefined" && ! HTMLElement.prototype.insertAdjacentElement){
    HTMLElement.prototype.insertAdjacentElement = function(where,parsedNode)
    {
        switch (where){
        case 'beforeBegin':
            this.parentNode.insertBefore(parsedNode,this)
            break;
        case 'afterBegin':
            this.insertBefore(parsedNode,this.firstChild);
            break;
        case 'beforeEnd':
            this.appendChild(parsedNode);
            break;
        case 'afterEnd':
            if (this.nextSibling) this.parentNode.insertBefore(parsedNode,this.nextSibling);
            else this.parentNode.appendChild(parsedNode);
            break;
        }
    }

    HTMLElement.prototype.insertAdjacentHTML = function(where,htmlStr)
    {
        var r = this.ownerDocument.createRange();
        r.setStartBefore(this);
        var parsedHTML = r.createContextualFragment(htmlStr);
        this.insertAdjacentElement(where,parsedHTML)
    }

    HTMLElement.prototype.insertAdjacentText = function(where,txtStr)
    {
        var parsedText = document.createTextNode(txtStr)
        this.insertAdjacentElement(where,parsedText)
    }
}
//----------------------------------------------------------------------------------------------------------


 //Node 추가
function _InsertNodes(_Nodes,vars){
 if (_Nodes){
 var tte= _Nodes.insertAdjacentHTML("beforeEnd",vars);
 }
 return tte;
}

//Element 추가
function _InsertElements(_Nodes,vars){
 if (_Nodes){
  var newObj=document.createElement(vars);
  var _ele = _Nodes.insertAdjacentElement("beforeBegin",newObj);
 }
 return _ele;
}

//Node 삭제
function _DeleteNodes(_Nodes){
 if (_Nodes){
  //_Nodes.removeNode(true);
  _Nodes.parentNode.removeChild(_Nodes); // ff에서 removeNode
  //alert(_Nodes.outerHTML)
  //_Nodes.removeChild(_Nodes)
  _Nodes.style.width=0;
  _Nodes.style.height=0;
 }
}


//Node 삭제
function _ReMoveNodes(_Nodes){
 if (_Nodes){
  _Nodes.removeNode(_Nodes);
 }
}
  //-->

function _InnerHtml(_Nodes,outhtml)
{
 if (_Nodes)
 {
 var _inner = _Nodes.innerHTML = outhtml;
 }

return _inner;
}
function test(){

//_InsertNodes(document.getElementById("gg"),"tt");
//_InnerHtml(document.getElementById("gg"),"<table border=1><tr><td>aaaaaaa</td></tr></table>");
//_InsertElements(document.getElementById("gg"),"tt");
_DeleteNodes(document.getElementById("gg"));
//_InsertElements(document.getElementById("kk"),"sss");
}

  </SCRIPT>



 <div onclick="test();" id='ff'>aaa</div>
 <div id='gg'>bbb</div>
 <div id='kk'>ccc</div>

Posted by 자스

obj.removeNode(obj) 혹은 obj.removeNode(true); 를 사용시

Ie 5,6,7 브라우져에서는 제대로 작동하지만 FireFox에서 이 메소드를 사용시

이 메소드가 없다는 에러메세지가 남는다.

FF에서 이메소드를 대체하는 방법은 아래와 같다.


obj.parentNode.removeChild(obj);

Posted by 자스

2007. 5. 4. 18:51 programing/javascript

규격

- 한글 번역 HTML 4.01 규격 : http://trio.co.kr/webrefer/html/cover.html


- 한글 번역 CSS 1 규격 : http://trio.co.kr/webrefer/css1/rec-css1.html


- 한글 번역 CSS 2 규격 : http://trio.co.kr/webrefer/css2/cover.html


- 한글 번역 XHTML 1.0 규격 : http://trio.co.kr/webrefer/xhtml/overview.html


- 한글 번역 XML 1.0 규격 : http://trio.co.kr/webrefer/xml/xml10.html

Posted by 자스

문서 다운로드는 아래 링크 :

http://www.mozilla.or.kr/docs/web-developer/web-standard-guide-2005.pdf


Posted by 자스

2007. 4. 27. 10:33 programing/javascript

JSON

XML 을 생성하기 위한 javascript 날코딩의 대안으로 JSON(Javascript Object Notation, www.json.org) 을 소개한다. JSON 은 텍스트 포맷기반의 경량 데이터 변환 포맷이다. 프로그래밍 언어에 독립적며, C 언어계열에 익숙한 데이터 구조 형식을 취하고 있다. JSON은 두가지 텍스트 포맷을 가지고 있는데, 첫번째는 name/value 쌍의 컬렉션 데이터 구조로 프로그래밍 언어로 따지면 object, record, struct 쯤 되겠다. 두번째는 정렬된 value 의 리스트형태로써 프로그래밍 언어로 비유하자면 배열이라고 보면 될 것이다.

JSON 의 데이터 구조는 많은 프로그램 언어에 의해서 지원되고 있기때문에 XML 보다는 이기종 시스템간의 이상적인 선택이 될 것이다. 추가적으로 JSON 은 표준 자바스크립트의 부류이므로 모든 웹 브라우저간에도 양립할 수 있는 것이다.

=====================================================================================================================

Object{} 으로 표시한다. 오브젝트에는 name/value 쌍이 콜론(:)  혹은 콤마(,) 로 구분되어져 있으며 순서는 없다.
 
Array[] 으로 표시한다.
        배열은 정렬된 value 가 콤마(,) 에 의해서 구분되어져 있으며,
        value 값은 스트링("" 으로 둘러싸야 함),
        숫자, true or false, null, object , array 가 올수 있으므로 배열의 구조는 계층적이라고 할 수 있다.

String은 유니코드 조합 및 백래쉬 이스케이프(\)를 사용할 수 있으며 '' 을 사용하여 character 를 표현할 수 있다.
스트링과 숫자는 C언어 혹은 자바의 스트링과 거의 흡사하지만 8진수 및 16진수 포맷은 지원하지 않는다.

공백을 name/value 쌍 사이사이에 사용할 수 있다.

=====================================================================================================================

Employ 라는 클래스(멤버로 firstName, lastName, employeeNumber, title)의 인스턴스를 JSON 을 이용해서 아래와 같이 표현해 볼 수 있다.
 
var employee = {
 "firstName"    : John,
 "lastName"     : Doe,
 "employNumber" : 123,
 "title"        : "Manager"
}
 
그러면 위 표현을 오브젝트 속성을 이용해서 아래와 같이 다룰 수 있다.
var lastName = employee.lastName;//lastName 에 접근
var title = employee.title;//title 에 접근
employee.emplyeeNumber = 456;//employeeNumber 를 456 으로 수정

=====================================================================================================================

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JSON Example</title>

<script type="text/javascript" src="json.js"></script>
<script type="text/javascript">

var xmlHttp;

function createXMLHttpRequest() {
    if (window.ActiveXObject) {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    else if (window.XMLHttpRequest) {
        xmlHttp = new XMLHttpRequest();
    }
}
   
function doJSON() {
    var car = getCarObject();
   
    //Use the JSON JavaScript library to stringify the Car object
    var carAsJSON = JSON.stringify(car);
    alert("Car object as JSON:\n " + carAsJSON);
   
    var url = "JSONExample?timeStamp=" + new Date().getTime();
   
    createXMLHttpRequest();
    xmlHttp.open("POST", url, true);
    xmlHttp.onreadystatechange = handleStateChange;
    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");   
    xmlHttp.send(carAsJSON);
}
   
function handleStateChange() {
    if(xmlHttp.readyState == 4) {
        if(xmlHttp.status == 200) {
            parseResults();
        }
    }
}

function parseResults() {
    var responseDiv = document.getElementById("serverResponse");
    if(responseDiv.hasChildNodes()) {
        responseDiv.removeChild(responseDiv.childNodes[0]);
    }
   
    var responseText = document.createTextNode(xmlHttp.responseText);
    responseDiv.appendChild(responseText);
}

function getCarObject() {
    return new Car("Dodge", "Coronet R/T", 1968, "yellow");
}

function Car(make, model, year, color) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.color = color;
}

</script>
</head>

<body>

  <br/><br/>
  <form action="#">
      <input type="button" value="Click here to send JSON data to the server"
        onclick="doJSON();"/>
  </form>
 
  <h2>Server Response:</h2>

  <div id="serverResponse"></div>

</body>
</html>

<3-18 jsonExample.htm 의 전체 소스 코드>


package ajaxbook.chap3;

import java.io.*;
import java.net.*;
import java.text.ParseException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.json.JSONObject;

public class JSONExample extends HttpServlet {

    /**
  *
  */
 private static final long serialVersionUID = 1L;

 protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        String json = readJSONStringFromRequestBody(request);

        //Use the JSON-Java binding library to create a JSON object in Java
        JSONObject jsonObject = null;
        try {
            jsonObject = new JSONObject(json);
        }
        catch(ParseException pe) {
            System.out.println("ParseException: " + pe.toString());
        }

        String responseText = "You have a " + jsonObject.getInt("year") + " "
            + jsonObject.getString("make") + " " + jsonObject.getString("model")
            + " " + " that is " + jsonObject.getString("color") + " in color.";

        response.setContentType("text/xml");
        response.getWriter().print(responseText);
    }

    private String readJSONStringFromRequestBody(HttpServletRequest request){
        StringBuffer json = new StringBuffer();
        String line = null;
        try {
            BufferedReader reader = request.getReader();
            while((line = reader.readLine()) != null) {
                json.append(line);
            }
        }
        catch(Exception e) {
            System.out.println("Error reading JSON string: " + e.toString());
        }
        return json.toString();
    }
}

<3-19 JSONExample.java 의 전체 소스 코드>


=====================================================================================================================
자바스크립트쪽 핵심코드를 먼저 살펴보자.

function getCarObject() {
    return new Car("Dodge", "Coronet R/T", 1968, "yellow");
}

function Car(make, model, year, color) {
    this.make = make;
    this.model = model;
    this.year = year;
    this.color = color;
}


위 코드는 설명이 별로 필요치 않을 것 같다. Car 객체를 만들어 주는 메소드이다.


function doJSON() {
    var car = getCarObject();
   
    //Use the JSON JavaScript library to stringify the Car object
    var carAsJSON = JSON.stringify(car);
    alert("Car object as JSON:\n " + carAsJSON);
   
    var url = "JSONExample?timeStamp=" + new Date().getTime();
   
    createXMLHttpRequest();
    xmlHttp.open("POST", url, true);
    xmlHttp.onreadystatechange = handleStateChange;
    xmlHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");   
    xmlHttp.send(carAsJSON);
}

위 코드를 보면 자바스크립트 car 객체를 생성한 후 JSON 자바스크립트 라이브러이의 stringify 를 사용해서 JSON 객체로 변환하고 있다. 나머지 로직은 POST 방식을 구현한 것이고 send(() 메소드에 JSON 객체를 넣어준다.


이번엔 서버쪽 프로그램을 확인해 보자.


JSONObject jsonObject = null;
try {
    jsonObject = new JSONObject(json);
}
catch(ParseException pe) {
    System.out.println("ParseException: " + pe.toString());
}

String responseText = "You have a " + jsonObject.getInt("year") + " "
 + jsonObject.getString("make") + " " + jsonObject.getString("model")
 + " " + " that is " + jsonObject.getString("color") + " in color.";


우선 서버 프로그램은 Http request 객체에서 JSON 문자열을 추출한다. 이렇게 추출된 문자열을 JSON 자바 라이브러리의 JSONObject 클래스를 생성할때 생성자의 파라미터로 입력된다. JSONObject 는 자동으로 JSON 문자열을 파싱하고 getXxx 메소드를 이용해서 여러 타입의 데이터를 추출할 수 있는 것이다.

출처 : http://blog.naver.com/lune23
Posted by 자스

레이어들이 세로로 나열된 상태에서...
위, 아래로 이동하며... 2개의 레이어 선택시 위치 교환까지 가능한 스크립트입니다.

다음이나 야후의 메인페이지에 구현된 기능이죠.

신기해서 따라해봤습니다. (성공하고 나서 낼름 이곳 메인 페이지에 적용햇지용..ㅋㅋ)

소스도 약간 길고.. 이해하기도 편하시라고 따로 샘플페이지를 만들었습니다.
샘플페이지를 열어보시고 소스보기 하시면 전체 필요한 소스가 보입니다.

자~ 소스를 보셨다는 가정하에~

필요한 부분은

1. Style 은..

<style type="text/css">
 .swapDivWrapper {
  padding:10px;
  padding: 10px;
  border: dotted 1px orange;
  width: 400px;
 }
 .swapDiv {
  position: relative;
 }
 .swapButtonU, .swapButtonD {
  cursor:pointer;
 }
 .swapCB {
  width: 10px; height: 10px; cursor:pointer;
 }
</style>
<!--[if IE]>
 <style type="text/css">
  .swapCB {
   margin-bottom: 3px;
  }
 </style>
<![endif]-->

이정도가 필수로 들어가야 하는부분입니다.

2. 스크립트는 상단에 들어있는 스크립트 전체가 필요합니다. 적용하실 페이지 상단에 넣어주세요.

3. 레이어들을 전체적으로 <div class="swapDivWrapper" id="swapDivWrap"> 로 감싸주셔야 합니다.

그리고 이동될 각각의 레이어들은 <div class="swapDiv" id="swap1"> 이런형식으로 한번더 감싸줘야 하구요.

id 는 당연히 중복되면 안되구요~  class 는 고치지 마세요.
그리고... 이동될 레이어안에서 원하는 위치에 버튼들을 넣어주실수 있습니다.

샘플에서 보이듯이..

<img class=swapButtonU height=12 alt="up arrow" src="up-arrow.gif" width=11 align=absmiddle border=0> <img class=swapButtonD height=12 alt="down arrow" src="down-arrow.gif" width=11 align=absmiddle border=0>

(위, 아래 화살표) 와

<input class=swapCB type=checkbox name=checkSwap> (체크버튼) 을 넣어주시면 됩니당.

그리고 마지막으로 페이지 하단에

<script language="javascript" type="text/javascript">
 /* <![cdata[ */
 var divSwap = new swapDiv('swapDivWrap');
 divSwap.mode = 1;
 divSwap.step = 10;
 divSwap.interval = 10;
 divSwap.init();
 /* ]]> */
</script>

처럼 추가해주시면 되는데요~ 하이라이트 된 아이디는 수정하셔도 되지만.. 두곳이 같아야 한다는걸 의미하죠~

divSwap.mode 는 0.1 부터 무한대입니다만.. 1보다 작으면 빠른시작--느린멈춤 이구요.. 1 이면 평범한 움직임이고.. 1보다 크면.. 느린시작--빠른멈춤의 움직임입니다.

divSwap.step 는 움직이는데 걸쳐가는 단계수입니다.. 많을수록 움직임이 부드럽겠지만..느리겟죠?

divSwap.interval 는 위에 지정한 단계수 사이의 실행간격입니다.. 역시나 크면 느려집니다.


자~ 이렇게 해서 성공하시면... 움직임이 생길때마다 쿠기에 그 순서가 기억되는데요....

php 나 기타 서버사이드 프로그램에서 쿠키를 읽어서 순서에 맞게 각각의 레이어를 출력해주시면 페이지 이동시에도 그 순서가 유지되겠죠? (출력버퍼링 사용)

1. 이동될 각각의 div 사이 사이에 <!--div split--> 이라고 코멘트태그를 넣었습니다..
2. 이동될 각각의 div에 아이디를 swap1 ~ spap6 이렇게 끝에 1부터 순차적으로 숫자를 넣었습니다.
3. 전체 div 가 시작되는 <div class="swapDivWrapper" id="swapDivWrap"> 의 밑줄에..

<?php
function arrangeDivs($buffer)
{
 $tmpbuffer = array();
 $divs = explode('<!--div split-->', $buffer);
 if(isset($_COOKIE['swapDivWrap_order'])) {
  $orders = explode(',', $_COOKIE['swapDivWrap_order']);
  if(count($orders) < 6) { // 6은 이동되는 레이어의 전체 갯수
   unset($_COOKIE['swapDivWrap_order']);
    return ($buffer);
  }
  foreach($orders as $key => $val) {
   $keyno = (substr(trim($val),-1) - 1);
   $tmpbuffer[] = $divs[$keyno];
  }
  $buffer = implode('<!--div split-->',$tmpbuffer);
 }
 return ($buffer);
}
ob_start("arrangeDivs");
?>

위 소스를 넣어주고...

전체 div 가 끝나는 부분인 </div> 의 윗줄에..아래 하이라이트된 소스를 넣었습니다.

<?php
ob_end_flush();
?>
</div>

그러나~ 그게.. 구조상 힘들수도 있고... 쉽게 적용할수 없을때가 있습니다...

그래서 현재 페이지 이동시 쿠키값을 읽어서 순서에 맞게 배열합니다.
(현재 샘플페이지 처럼... 레이어 몇개 이동하고나서 새로고침해보시길....)

  if (!getCookie(self.cookieName)) {
   self.divOrder = self.divOrderArray.join(',');
   setCookie(self.cookieName,self.divOrder,365);
  } else {
   var divOrderSaved = getCookie(self.cookieName);
   if (divOrderSaved != self.divOrderArray.join(',')) {
    var divOrderArraySaved = divOrderSaved.split(',');
    calculateGap(divOrderArraySaved, self.divOrderArray);
    for(var i=0; i < divOrderArraySaved.length; i++) {
     var obj1 = document.getElementById(divOrderArraySaved[i]);
     var startPos = getStylePos(obj1);
     var endPos = newPos[obj1.id];
     elementMover(obj1,startPos,[0,endPos],self.step,self.interval,self.mode);
    }
   }
  }

스크립트 상단부에 저런 부분인데여.... 서버에서 출력처리 하셨거나.. 페이지 이동시 스르륵 순서잡는게 싫으시다면.. 
위에서 else { ...생략... } 를 지워주시면 되겠습니다.



출처 : http://www.alik.info/gnu/bbs/tb.php/alik/1033

Posted by 자스
페이지가 언로드되기 바로 전에 발생한다.

웹 페이지나 이미지 등을 다 읽어 들이면 onload 이벤트가 발생되고, 페이지를 닫거나 다른 페이지로 가면 그 페이지에서 이탈하므로 onunload 이벤트가 발생된다.

  • 현재의 윈도우를 닫았을 때.
  • 주소 입력, 즐겨찾기등을 사용하여 새로운 주소로 이동하였을 때.
  • '뒤로', '앞으로', '새로고침', ''등의 단추를 클릭했을 때.
  • 다른 웹 페이지를 참조하는 윈도우의 연결 anchor를 클릭했을 때.
  • anchor.click 메서드를 실행시켰을 때.
  • documentwrite 메서드를 실행했을 때.
  • documentopen 메서드를 실행했을 때.
  • documentclose 메서드를 실행했을 때.
  • windowclose 메서드를 실행했을 때.
  • 윈도우 이름으로 사용 가능한 _self 값을 제공하면서 window.open 메서드를 실행했을 때,
  • window.navigateNavigateAndFind 메서드를 실행했을 때.
  • locationreplace 메서드를 실행했을 때.
  • location.reload 메서드를 실행했을 때.
  • location.href 속성에 새로운 값을 지정했을 때.
  • INPUT type=submit 제어나, submit 메서드를 실행하여, form에서 주소를 지정하는 action 애트리뷰트로 송신(submit)했을 때.
Posted by 자스

2007. 4. 15. 02:43 programing/php

트랙백

트랙백 사용방법

트랙백(Trackback)은 매우 간단한 구조와 원리를 가지고 있는 블로그간 커뮤니케이션 기능입니다.

트랙백이란?

트랙백이란, 쉽게 말씀드려 "내가 작성하는 글을 다른사람에게 알리는 기능"입니다.

B 라는 사람이 A 라는 사람의 글에 대해서 의견을 남기는 방법으로 현재는 그 글에 [덧글]을 적는 방법 밖에는 없습니다. 그러나 덧글은 장문의 글을 작성하기에는 적합하지 않은데다가, 같은 내용을 내 이글루(블로그)에도 남기고 싶을 때, 다시한번 글을 등록해야 하는 번거로움이 있습니다. 그래서 등장한것이 바로 트랙백 기능 입니다.


트랙백 적용 원리 및 순서

A가 어떤 주제에 대해 글을 올렸다고 생각해 보세요. B라는 사용자가 그 글을 본 후, 그 글에 관련된 글을 자신의 이글루(블로그)에 올리려고 합니다. B는 새글을 쓸 때 새글올리기 하단에 있는 트랙백 주소 라는 항목에 관심을 가졌던 A글의 트랙백 주소를 입력하고 글을 작성합니다.
글을 등록하는 순간에, 그 내용은 자동적으로 서버에 기록이 되어 A 글의 하단 트랙백 항목에 등록되게 됩니다.
트랙백에 등록되면 A를 포함한 A이글루(블로그)를 방문하는 모든 사람이 그 내용을 확인 할 수 있습니다.


이글루스에서 트랙백 사용하기

1. 각 글의 트랙백주소 및 트랙백 보기


2. 새글 작성시 트랙백 주소 입력
※ 이글루스의 트랙백 프로토콜은 국제규격을 따르며 다른 블로그 툴간의 호환이 완벽하게 지원됩니다. 이글루스와 Movable Type, pMachine, Nucleus, B2 Blog 등의 트랙백을 지원하는 모든 블로그 프로그램에 트랙백 핑을 보내거나 해당 블로그 프로그램으로부터의 트랙백 핑을 받을 수 있습니다.

다른 궁금한 사항은 webmaster@egloos.com 으로 메일을 보내주시기 바랍니다.
Posted by 자스

2007. 4. 12. 11:28 programing/javascript

RegExp

regObj=new RegExp('pattern'[,'flags'])
RegExp 개체는 정규식(regular expression)의 패턴(pattern)을 갖고 속성들메서드들을 사용하여 일치하는 문자열을 찾는다. 정규식 문구가 사용되면 언제나 속성들을 갖는 사전에 정의된 RegExp 개체가 사용되고, 각 개체들마다 사용자 정의를 갖는다.
어느 경우나 정규식 패턴을 지정해야 하며, g, i, m 세가지 가능한 프래그를 선택적으로, 복합적으로 사용 할 수 있다.
flag 설명
g 발생할 모든 pattern에 대한 전역 검색
i 대/소문자 구분 안함
m 여러 줄 검색
'g' 모든 패턴 검색(global match), 'i' 대/소문자 구분 안함(ignore case), 'gi' 그 두가지.


EX)

/***********************************************************
 함수명  :replace123(str1, str2, str3)
 처리내용  :str3에서 str1을 str2로 변환하여 반환
***********************************************************/
function replace123(str1, str2, str3){
    var rgexp = new RegExp(str1,"g");
    return (str3.replace(rgexp, str2));
}
Posted by 자스
사용자 삽입 이미지
Javascript]
document.readyState
 
위의 인터넷 상태표시줄에 로딩이 완료되면
document.readyStatecomplete를 반환한다.
 
로딩 완료시점만 체크하는 가라(?) 로딩바를 띄울때 자주 사용되고 있다.
 
 
if (document.readyState == "complete"){
        //로딩바(div) 사라지기
}else{
        //로딩바(div) 나타내기
}
Posted by 자스
이전버튼 1 2 3 이전버튼

블로그 이미지
자스

공지사항

Yesterday
Today
Total

달력

 « |  » 2025.8
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

최근에 올라온 글

최근에 달린 댓글

글 보관함