순서가 중요한 명령문

ex명령문의 순서가 중요한 자바예제

 data = ReadData();

results = CalculateREsultsFromData(data);

PrintResults(results);

위 코드는 반드시 순서를 지켜야 한다

ex 명령문의 순서가 중요하지만 덜 분명한 자바예제

revenue.ComputeMonthly();

revenue.ComputeQuarterly();

revenue.ComputeAnnual();

코드만으로는 순서의 의존성이 명확하지 않다

ex 명령문의 순서 의존성이 감추어져 있는 VB예제

ComputeMakrteingExpense

ComputeSalesExpense

ComputeTravelExpense

//...

위 코드를 보고서는 순서 의존성을 전혀 알수 없다.

명명문들이 특정한 순서대로 작성되어야 한늬 의존성을 갖고 있을때, 의존성을 분명히 하기 위한 단계를 밟아야 한다.

  • 의존성이 분명하도록 코드를 구성한다.
  • 의존성이 분명하도록 루틴의 이름을 작성한다.
  • 의존성을 분명히 하기 위해서 루틴 매개변수를 사용해라.

    ex 데이터가 순서의 의존성을 말해주는 VB예제

    InitializeExpenseData(expenseData)   //초기화는 무엇보다 먼저 실행되어야 하니까 이름도 초기화를 의미하게 지어주는 게 센스

    ComputeMarketingExpense(expenseData)

    ComputeSalesExpense( expenseData)

    ComputeTravelExpense (expenseData)

    ex 루틴을 expenseData를 입력으로 받고 갱신된 expenseData를 출력으로 반환하는 함수로 변환하여 코드의 순서 의존성이 있음을 보다 명확하게 만든다

    expenseData = InitializeExpenseData(expenseData)  

    expenseData = ComputeMarketingExpense(expenseData)

    expenseData = ComputeSalesExpense( expenseData)

    expenseData = ComputeTravelExpense (expenseData)

  • 의존성이 분명하지 않은 부분은 주석으로 문서화한다
  • assertion이나 오류처리 코드로 의존성을 검사한다

 

순서가 중요하지 않은 명령문

순서가 중요하지 않은 경우에는 일반적인 근거치 법칙, 즉 관련된 작업을 함께 두는 법칙을 따르는 것이 가독성, 성능, 유지 보수에 유리하다

  • 코드를 하향식으로 읽을수 있도록 작성하기.
  • 연관된 명령문 그룹화하기.

 

이 글은 스프링노트에서 작성되었습니다.

by 무위자연 2008. 1. 19. 15:54

조건문은 다른 명령문의 실행을 제어하는 명령문이다. 즉 if, else, case, switch 와 같은 명령문으로 분기된다.

 

if 문

if- then 명령문

  • 일반적인 경우에 대한 코드를 먼저 작성한 다음 특별한 경우를 작성한다
  • 동치에 대해서 정확하게 이동하도록 한다 - >= 대신 > 를 사용하거나 <= 대신 <를 사용하면, 배열에 접근하거나 루프 인데스를 계산할때 하나 차이로 오류(off-by-one)를 만드는 것과 같다.
  • 정상적인 경우를 else가 아니라 if문 다음에 입력한다 - 정상적으로 처리되는 경우를 먼저 작성한다. 이는 결정으로부터의 결과를, 가능한 한 결정을 하는 위치와 가깝게 코드를 작성하는 일반적인 우너칙과 일치한다
  • if 절 다음에는 의미 있는 명령문을 작성한다.

    ex if절이 null인 자바 예제

    if( someTest) ;

    else { // 작업처리

    }

    ex null if절이 변환된 자바예제

    if( !someTest) {작업처리}

  • else절을 고려한다 - 만약 if문이 필요하다면 if-then-else문이 필요 없는지 고려한다. else인 경우를 고려했다는 것을 표시하기 위해 널 절이라도 추가해준다.
  • 정확성을 위해서 else절을 테스트한다
  • if와 else절의 역을 검사한다 - 로직상에 두개의 절 내용이 바뀌는 오류를 확인한다

연속적인 if-then-else 문

case문을 지원하지 않거나 부분적으로만 지원하는 언어에서는 종종 if-then-else테스트를 연속해서 작성하게 될 것이다. 다음은 이것에 대한 지침이다

ex 문자를 분류하기 위해서 일련의 if-then-else를 사용하는 C++예제

if(inputCharacter < SPACE){

 characterType = CharacterType_ControlCharacter;

}

else if {

inputCharacter == '' ||

inputCharacter == ',' ||

inputCharacter == '.' ||

inputCharacter == '!' ||

inputCharacter == '(' ||

inputCharacter == ')'){

chracterType = CharacterType_Punctiation;

}

else if( '0' <= inputCharacter && inputCharacter <= '9') {

characterType = CharacterType_Digit;

}

else if(('a' <= inputCharacter && inputCharacter <= 'z') ||

('A' <= inputCharacter && inputCharacter <= 'Z')){

characterType = CharacterType_Letter;

}

  • 복잡한 테스트를 불린 테스트 호출로 단순화시킨다.

    ex 불린 함수 호출을 사용한 일련의 if-then-else C++예제

    if( IsContorl( inputCharacter))

    {

    chracterType = ChracterType_ControlCharacter;

    }

    else if( IsPunctuation( inputCharacter)){

characterType = CharacterType_Punctuation;

}

else if( IsDigit( inputCharacter)) {

    characterType = CharacterType_Digit;

}

else  if(IsLetter( inputCharacter )){

characterType = CharacterType_Letter;

}

  •  
  • 가장 흔한 경우를 앞에 놓는다 - 가장 흔한 경우를 앞에 놓음으로써, 다른 사람이 일반적인 경우를 찾기 위해서 읽어야 하는 예외적인 상황 처리코드의 양을 최소화할수 있다 그리고 가장 흔한 경우를 찾기 위한 코드 테스트의 수를 최소화하여 효율성을 향상시킨다.

    ex 가장 흔한 경우를 제일 먼저 테스트하는 C++예제

    if(IsLetter( inputCharacter )){ //가장 흔한 테스트가 이제 제일 먼저 수행된다

    characterType = CharacterType_Letter;

    }

    else if( IsPunctuation( inputCharacter)){

    characterType = CharacterType_Punctuation;

    }

    else if( IsDigit( inputCharacter)) {

        characterType = CharacterType_Digit;

    }

    else if( IsContorl( inputCharacter)) //가장 흔하지 않은 테스트가 이제 제일 나중에 실행된다

    {

    chracterType = ChracterType_ControlCharacter;

    }

  • 모든 경우를 다루었는지 확인한다 - 마지막 else 절에는 계획하지 않은 경우를 잡기 위해 오류 메시지나 assertion을 작성하도록 한다.
  • 만약 언어가 지원한다면, if-then-else체인 대신 다른 구조를 사용한다. - case문은 if-then-else체인보다 읽기 쉽고 작성하기 쉽다.

 

CASE문

가장 효율적인 case순서의 선택

  • 알파벳 순으로 또는 숫자순으로 case를 나열한다 - 가독성을 높일수 있다
  • 가장 정상적인 경우를 앞에 놓는다
  • 빈도에 따라서 case를 나열한다

case 문 사용 팁

  • case문이 하는 일을 간단하게 유지한다
  • case문에서 사용하기 위해서 phony 변수를 채우지 않는다 - case문은 쉽게 분류될수 있는 간단한ㅇ 데이터에 대해서 사용되어야 한다. 만약 데이터가 간단하지 않다면, 대신 if-then-else체인을 사용한다. 포니변수(가짜변수)들은 혼란을 야기할수 있기때문에 사용하지 않아야 한다.

ex 포니 case변수를 생성한 자바예제

action = userCommand[0];

switch(action) {

case 'c':

Copy();

break;

case 'd':

DeleteCharacter();

break;

case 'f':

Format();

break;

case 'h':

Help();

break;

//...

default:

HandlingError();

}

이 경우에 case문은 의도와 다르게 동작 가능성이 높다. 사용자가 copy()를 입력할수도 있지만 c로 시작하는 전혀 다른 문장을 입력했을때도 copy()가 실행된다, 올바른 맵핑이 이루어질수 없다. 이런 경우 포니변수 대신에 문자열 비교를 위한 if-then-else체인을 사용하는 것이 좋다

  • 타당한 기본 값을 찾고자 하는 경우에만 dafault절을 사용한다
  • 오류를 검출하기 위해서 default 절을 사용한다
  • C++와 자바에서는 case문의 끝에서 아래로 내려가는 경우를 피한다 - 즉 각 case끝에는 break;를 넣어줘야 한다
  • C++에서는 case문의 끝에서 분명하고 확실하게 아래로 떨어지는것(flow-through)을 확인해야 한다

 

이 글은 스프링노트에서 작성되었습니다.

by 무위자연 2008. 1. 19. 15:54

루프의 종류선택

  • 계수형 루프(coiunted loop) 는 특정한 횟수만큼 수행된다
  • 계속 판단 형 루프(continuously evaluated loop) 얼마나 실행될 것인지를 미리 알지 못하며, 반복할 때마다 중단할지를 검사한다.
  • 무한 루프(endless loop)는 일단 시작되면 끝없이 실행된다.
  • 반복자(iterator)루프는 컨테이너 클래스에 있는 각 요소들에 대해서 한번씩 수행한다

루프의 종류는 유연성에 의해서 차별화된다. 즉, 루프가 지정된 횟수만큼 실행되는지 또는 반복마다 완료 조건을 테스트할 것인지에  따라서 달라진다

 

Loop-With-Exit 루프를 사용하는 시기

종료조건이 루프의 시작이나 끝이 아니라 중간일 경우에 사용

 

이런 루프를 사용할때 주의점

  • 모든 조건들을 한 곳에 입력한다.
  • 조건을 분명히 하기 위해서 주석을 쓴다

 

for 루프를 사용하는 시기

for루프는 지정한 횟수만큼 실행되는 루프가 필요할때 사용한다. 내부적인 루프제어가 필요하지 않은 간단한 작업에 대해서 for루프를 사용한다. 루프제어가 컨테디어에 있는 요소들을 반복하는 것과 같이,

간단한 증가나 감소인 경우에 for를 사용한다. for루프의 핵심은 루프의 맨위에서 설정한 다음, 잊어버리면 된다는 점이다. 루프를 제어하기 위해서 루프내부에서 아무것도 할 필요가 없다.

만약 실행 중에 루프를 빠져나가야 한다면 while 루프를 선호해라.

 

루프의 제어

루프를 다룰때 생기는 문제들 - 잘못된 루프 초기화 , 루프 초기화 생략 , 연산자 혹은 루프와 관련된 다른 변수들의 초기화 생략, 부적절한 중첩, 잘못된 루프 종료, 루프 변수를 증가시키는 것을 잊거나

변수를 잘못 증가시키는 것, 그리고 루프 인덱스에서 배열 요소를 잘못 인덱스 하는 것 등

이것을 방지하기 위한 습관 - 루프 영향을 미치는 요소의 수를 최소화한다. 단순화! 단순화! 단순화! 루프의 내부를 마치 별도의 루틴처럼 처리한다. 될수 있는 한 제어부분을 푸의 밖에서 입력하고 루프 몸체 내에서

실행되어야 하는 조건들을 분명히 한다

루프 진입하기

  •  한 위치에서만 루프에 진입한다
  • 루프가 시작하기 바로 전에 초기화 코드를 입력한다 - 근접성의 원칙에 따른 것. 수정시 오류를 쉽게 피할수 있다. 루프 초기화명령문을 루프 근처에 둔다
  • 무한 루프는 while(true)를 사용한다. - 어떤 프로그래머는 for( ;; )를 대안으로 쓴다
  • 적절할때 for루프를 택한다
  • while루프가 더 적절할때 for루프를 사용하지 않는다

ex while루프를 억지로 for루프 헤더에 밀어 넣은 C++예제

//파일에서 모든 레코드를 읽는 것

for( inputFile.MoveToStart(), recordCount = 0; !inputFile.EndOfFile(); recordCount++) inputFile.GetRecord();

for 루프헤더는 루프 제어 명령문, 즉 루프를 초기화하고 종료하거나 종료의 상황으로 접근하는 명령문을 위해서 사용한다. inputFile.GetRecord()명령문이 루프를 종료상황에서 접근시키고 있지만, recordCount명령문은 그렇지 않다

이 명령문들은 루프의 진행을 제어하지 않는 보조 관리 명령문이다. 루프헤더에 recordCount명령문을 이동시키고, inputFilr.GetRecord()명령문을 밖으로 빼낸 것이 잘못된 것이다. recordCount가 루프를 제어하는 듯한 오해를 만들고 있다.만약 이 경웨 while대신 for를 쓰고 싶다면 루프제어 명령문을 루프헤더에 입력하고 나머지를 모두 밖으로 빼내도록 한다

ex 푸르 헤더에서 논리적인 조건을 자유롭게 사용한 C++예제

recordCount = 0;

for( inputFile.MoveToStart(); !inputFile.EndoOfFile(); inputFile.GetRecord()) recordCount++;

ex while 루프를 적절하게 사용한 C++예제

inputFile.MoveToStart();

recordCount = 0;

while(!inputFile.EndOfFile())

{

inputFile.GetRecord(); recordCount++;

}

 

루프의 중간 부분 처리하기

  • 루프에 있응 명령문들을 둘러싸기 위해서 중괄호를 사용한다
  • 빈 루프를 피한다
  • 루프에서 보고관리 작업들(housekeeping)은 루프의 시작이나 끝에 놓는다. - 루프의 보조관리 작업은 루프가 처리해야 하는 일이 아니라 루프를 제어하기 위한 것이 주된 목적인 표현식, 즉 i= i+ 1 , j++ m같은 표현식이다.
  • 루프가 하나의 기능만 수행해야 한다 - 루프가 한번에 두가지 일을 하기 위해서 사용될수 있다는 사실만으로 두가지 기능을 동시에 수행해도 된다는 것은 정당화되지 못한다. 하나의 루프는 반드시 한가지 일을 수행해야 한다

 

루프의 종료

  • 루프가 종료되는 확인한다 - 루프가 종료되는지 반드시 확인해야 한다
  • 루프 종료조건을 명확하게 한다
  • 루프를 종료하기 위해서 for루프의 인덱스를 조작하지 않는다

    ex루프 인덱스를 조작하는 자바예제

    for(iint i = 0; i < 100; i++){

//코드들

if(...){ i = 100} -> 여기서 조작하고 있다!

//코드들2

}

for루프를 설정할때, 루프 카운터는 사용이 금지된다 루프의 종료조건을 더 제어하기 위해서는 while루프를 사용한다

  • 루프인덱스의 마지막 값에 의존하는 코드를 피한다 - 루프가 끝난 후에 루프의 인덱스값을 사용하는 것은 나쁜 방법이다. 이 값은 루프가 정상적인 종료할때와 비정상종료일때도 다를수 있다. 가독성도 떨어진다.  루프 내에서 적절한 순간에 최종값을 변수에 할당해서 사용하는 것이 좋은 코드이다.쓰기도 읽기도.
  • 안전한 카운터를 사용한다 - 안전한 카운터는 루프가 너무 많이 실행되었는지를 결정하기 위해서 반복될때마다 증가시키는 변수이다. 만약 오류가 발생하면 치명적인 영향을 미치는 프로그램이 있다면, 모든 루프의 종료를 보장하기 위해서 안전한 카운터를 사용할수 있다.

ex 안전한 카운터를 사용할 수 있는 루프에 대한 C++예제

do{

node = node -> Next; //...

}while(node->Next != NULL);

ex 위의 예제에 안전한 카운터를 추가한 예제

safetyCounter = 0;

do{

node = node->Next;

//...

safetyCounter++;

if(safetyCounter >= SAFETY_LIMIT){

Assert("안전한 카운터 오류");

}

//...

}while(node->Next != NULL)

안전한 카운터를 만병통치약이 아니다. 한번에 하나씩 코드에 추가한다. 안전한 카운터는 복잡도를 증가시키고 추가적인 오류를 야기할수 있다. 안전한 카운터가 모든 루프에서 사용되지 않기 때문에, 안전한 카운터를 사요용하는 부분에 있는 루프를 수정할때 빼먹을수 있다.

  • 루프 일찍 종료하기

    • while문에서는 boolean플래그보다는 break문을 사용해라
    • 루프내에 수많은 break문이 산재되는 것을 주의한다
    • 루프의 앞부분에서 테스트를 위한 목적으로 continue를 사용한다 - 각 순회에서 필요없는 부분에 대한 연산을 빼고 진행할수 있다.
    • 언어에서 continue를 지원하지 않는 다면 레이블 break구조를 사용한다.

do {

switch()

{

case A:

if(){

//...

break;   //레이블 break대상이 분명하다

}

}

}while(...);

break와 continue를 신중하게 사용한다.

 

종결점 확인

우리가 루프에 가지는 관심사는 세가지 경우이다. 첫번째, 마지막, 중간에 임의번째이다. 이것이 정상적인 절차를 거친 것인지 확인하기 위한 과정이  효율적인 프로그래머와 아닌 사람이 차이가 난다. 효율적인 프로그래머는 머리에서 돌려보고 손으로 계산해 보는 것이 오류를 찾는데 도움을 준다. 비율적인 프로그래머는 우너하는 조합을 찾을때까지 무작정 실험하는 경향이 있다. 만약 루프가 예상했던 대로 작동하지 않는 다면, 비효율적인 프로그래머는 < 기호를 <=로 바꾼다. 만약 여전히 작동하지 않는 다면, 루프 인덱스에 1을 더하거나 뺀다. 결국 이러한 접근 방법은 우연일뿐만 아니라 더 큰 오류를 만들수 있다. 프로그래머는 프로그램이 왜 정확한지 알지 못하는 결과를 초래한다.

머리로 돌려본다는 것은 여러분이 코드가 어떻게 동작하는지 추측하지 않고 이해하고 있다는 것을 의미한다

 

루프 변수사용

  • 배열과 루프에 한계를 두기 위해서 서수나 열거형을 사용하라
  • 읽기 쉬운 중첩 루프를 작성하기 위해서 의미 있는 변수이름을 사용해라
  • 루프 인덱스 혼선(cross-talk)을 피하기 위해서 의미 있는 이름을 사용해라. - 동일한 이름의 변수를 다르게 사용하는 경우에 혼란을 야긴한다
  • 루프 인덱스 변수의 범위를 루프 자체로 제한하라 - 루프안에서 사용하는 변수를 루프 밖에서 사용하지 마라

 

루프가 얼마나 길어야 할까?에 대한 지침

  • 한군에 볼수 있도록 루프의 길이를 짧게 만들어라
  • 중첩을 3수준으로 제한하라
  • 긴 루프의 내부 루프를 루틴으로 이동하라 - 만약 루프가 잘 설계되었다면, 루프 내에 있는 코드를 루프 내에서 호출하는 하나 이상의 루틴으로 이동시킬수 있다
  • 길이가 긴 루프는 특히 명료하게 작성하라 - 길이가 길수록 복잡해 보인다. - 만약 길이가 짧은 루프를 작성한다면 break와 continue 여러개의 탈줄점(exit) 복잡한 종료조건과 같은 위험한 제어 구조를 사용할수 있다

 

 

루프를 쉽게 작성하는 법 - 안에서부터 밖으로

루프를 쉽게 작성하기 위해서는 다음과 같은 순서로 작성한다

한 문장으로 시작한다. 그 경우를 문장으로 작성한 다음에 들여쓰기하고 그 문장 주위에 루프를 입력한다. 그리고 문장을 루프 인덱스나 계산 표현식으로 바꾼다. 기능이 완성될때까지 이 과정을 반복한다.

작업을 마치고 난 후 필요한 모든 초기화 작업을 추가한다. 간단한 경우에서 시작해서 일반화하는 쪽으로 작업하기때문에, 이러한 코드 작성방식을 안에서 밖으로 진행하는 방식을 생각할수 있다.

 

보험회사에서 사용할 프로그램을 가정해보자. 이 프로그램은 고객의 나이와 성에 따라서 달라지는 보험료 표를 갖고 있다. 해야 할 일은 보험료를 계산하는 루틴을 작성하는 것이다. 목록에 있는 각각의 사람에 대한

보험료를 얻어서 총계에 더하는 루프가 필요하다.

  1. 주석으로 루프의 몸체에 수행해야 하는 단계를 작성한다. 문법의 세부 사항과 루프인덱스, 배열 인덱스 등에 대해서 신경쓰지 않으면, 처리해야 하는 일을 쉽게 적을수 있다.

    1단계 - 루프를 안에서부터 밖으로 작성하는 법 - 표에서 보험료를 읽어온다

    • 총계에 보험료를 더한다
  2. 전체 루프를 작성하지 않는 범위내에서 루프 몸체이 있는 주석을 코드로 변환한다 이 경우에는 한 사람의 보험료를 얻어서 총계에 보험료를 더한다. 추상적인 데이터보다는 실질적이고 구체적인 데이터를 사용한다.

    2단계 - rate = table[]

               totalRate = totalRate + rate;

    이 예제는 table이 보험료 데이터를 보관하고 있는 배열이라고 가정하고 있다. 처음에는 배열의 인덱스에 대해서 걱정할 필요가 없다. rate는 보험료 표에서 선택된 보험료 데이터를 보관하고 있는 변수이고 totalRate는 보험료의 총계를 보관하는 변수이다

  3. 다음으로 table배열에 인덱스를 입력한다

    3단계   - rate = table[census.Age ][ census.Gender ]

                totalRAte = totalRate + rate

    배열은 나이와 성으로 접근되기때문에 인자를 주었다. census가 그룹안에 있는 사람들에 대한 정보를 보관하는 구조체라고 가정하고 있다

  4. 다음 단계는 지금까지 작성한 명령문에 루프를 작성하는 것이다. 이 루츠는 그룹에 있는 사람들에 대한 보험료를 계산해야 하기떄문에 사람들 인덱스로 사용한다

    4단계 For person = firstPerson to lastPerson

                  rate = table [census.Age, census.Gender ]

                 totalRate = totlaRate + rate;

            end For

  5. 이제 적절한 들여쓰기를 한 후에 census변수가 사람마다 달라지므로 적절하게 생성되어야 한다

    For person = firstPerson to lastPerson

                  rate = table [census[person].Age, census[person].Gender ]

                 totalRate = totlaRate + rate;

            end For

  6. 마지막으로 초기화코드를 작성한다. 이경우네는 totalRAte변수가 초기화되어야 한다

    totalRate = 0;

    For person = firstPerson to lastPerson

     

                  rate = table [census[person].Age, census[person].Gender ]

     

                 totalRate = totlaRate + rate;

     

            end For

     

 

 

 

이 글은 스프링노트에서 작성되었습니다.

by 무위자연 2008. 1. 19. 15:53
<object width='380' height='380'><param name='movie' value='http://www.mixbook.com/flash/mixbook_albums.swf?b=32435&k=5aHzydMDoU&mode=production&bid=32435&autoplay=true' /><param name='wmode' value='transparent' /><param name='FlashVars' value='b=32435&k=5aHzydMDoU&mode=production&bid=32435&autoplay=true' /><embed src='http://www.mixbook.com/flash/mixbook_albums.swf?b=32435&k=5aHzydMDoU&mode=production&bid=32435&autoplay=true' FlashVars='b=32435&k=5aHzydMDoU&mode=production&bid=32435&autoplay=true' type='application/x-shockwave-flash' wmode='transparent' width='380' height='380'></embed></object><br/>  <a href='http://www.mixbook.com/books?bid=32435'>View this book full size or get a printed copy at Mixbook</a><br/>
by 무위자연 2008. 1. 17. 15:05

 뭔가가 조금 어색하긴 하다

 

티스토리랑 이글루스의 오픈 API를 지원하는지는 정말 몰랐네 - 유해진씨가 FTTH를 정말 몰랐던거 만치나 ㅋ

 

스프링노트를 사용하면

 

스프링노트와 이글루스와 티스토리를 한번에 관리...

 

까지는 아니어도 글을 남길여지는 있구ㅡㅁ

이 글은 스프링노트에서 작성되었습니다.

by 무위자연 2007. 9. 14. 14:23
 Blogger API : Pyra Lab에서 개발. blogger란 개념을 만들어냈으나
자금난으로 구글에 인수되었고 blogger.com 이 탄생했다.

metaWeblog API : Userland software에서 blogger API가 가지고 있는 치명적인 결함, 즉
metadata처리에 대한  점을 보완하기 위해 만들었다.

movable Type : six apart라는 회사가 자사 블로그의 퍼블리싱을 위해 제 3의 API를 만들었고
이름을 movable Type이라 지었으며 movable Type.org로 운영하고 있다. 사실에 의한 표준이 되고 있다.-미국을 중심으로- 이 회사는 movable type을 내세우며 태터툴즈같은 설치형 블로그를 배포
하고 있으며 티스 토리와 같은 서비스형 블로그를 통한 기업블로그 시작을 공략하고 있다.
by 무위자연 2007. 8. 10. 15:01
내 블로그의 트랙백을 이용해보기
버전임다
by 무위자연 2007. 8. 1. 11:53

이건 무슨 노래일까요?

여러개의 주크박스가 올라갈수도 있고

하나의 주크박스에 여러개의 노래를 넣을수도 있다
by 무위자연 2007. 8. 1. 11:27
by 무위자연 2007. 8. 1. 11:09

이번에는 되려나 모르겠네

구글독스에 이미지를 넣는 것이 와 이리 오래 걸리는건지...

이게 기술의 구글이더냐-_-

by 무위자연 2007. 7. 31. 12:10