나도 맹글었다. PathUI SVG 버전
2011/12/07 20:59오랜만에 삼각함수 검색했다. ㅇㅎㅎ
코드 좀 정리해서 모듈로 배포해야지.
샘플 페이지는 >>> 여기에
몇가지 코드 정리할 필요가 있다.
1) 옵션을 뺄수있는 설정들 정리
2) 주석 정리
3) 모듈 테스트
주석빼면 100줄도 안되네.. ㅇㅎㅎ
Trackback URL : http://miconblog.com/tc/sohn/trackback/685
Trackback URL : http://miconblog.com/tc/sohn/trackback/685
RegExp.test() - Boolean 값을 리턴
RegExp.exec() - 매칭된 값을 Array로 리턴
String.split() -
String.match() -
String.replace() -
String.search() -
var str = "테스트 테스트1 테스트2 테스트3 테스트4";위와 같이 실행하면, test()는 true, exec()는 ["테스트1"] 배열을 반환합니다.
var regx = /테스트\d/;
regx.test(str); // true
regx.exec(str); // ["테스트1"]
var str = "테스트 테스트1 테스트2 테스트3";뭐가 다른지 감이 오나요?.. exec()가 뱉어내는 리턴값을 유심히 보세요. 아직 모르시겠나요?
var regx = /(테스트\d)/;
regx.test(str); // true
regx.exec(str); // ["테스트1", "테스트1"]
RegExp.$1; // "테스트1" - test(), exex() 모두 같음.
var str = "테스트 테스트1 테스트2 테스트3";
var regx = /(테스트)\s(테스트\d)/;
regx.exec(str); // ["테스트 테스트1", "테스트", "테스트1"]
var str = "테스트 테스트1 테스트2 테스트3";자~~ 이젠 어떤 차이가 있지는 아시나요? 여전히 모르시겠다구요?
var regx = /(?:테스트\d)/;
regx.test(str); // true
regx.exec(str); // ["테스트1"]
RegExp.$1; // "" - test(), exex() 모두 같음.
var str1 = "No pain, No gain!";즉, "g 옵션을 쓰면, 모든 패턴을 찾게 된다." Global 의 G 가 바로 그 g 옵션인거죠..
var str2 = str1.replace(/ain/g, "XXX");
// str2 = "No pXXX, No gXXX!"
var str = "테스트 테스트1 테스트2 테스트3";g 는 글로벌 옵션이니까,.. 저렇게 나와야 하는게 아닐까?.. 하는거죠!!
var regx = /(테스트\d)/g;
regx.exec(str); // ["테스트1", "테스트2", "테스트3"] 일까요???????
var str = "테스트 테스트1 테스트2 테스트3";어랏?.. 저렇게 나올껄 예상하셨나요? 올~~ 예상했다면, 당신은 규식이를 잘 하는 분입니다.
var regx = /(테스트\d)/g;
regx.exec(str); // 1번 실행, ["테스트1", "테스트1"]
regx.exec(str); // 연속해서 두번 실행, ["테스트2", "테스트2"]
regx.exec(str); // 연속해서 세번 실행, ["테스트3", "테스트3"]
RegExp.$1; // "테스트3"
Trackback URL : http://miconblog.com/tc/sohn/trackback/554
Trackback URL : http://miconblog.com/tc/sohn/trackback/502
imeMode 속성은, IE 전용 속성인데,
FF3 에서부터는 해당 속성을 지원해주는듯하다..
https://developer.mozilla.org/En/CSS/Ime-mode
하지만.. 테스트는 안해봤다. 테스트 해본 사람들에 의하면,..
아직 안된다고 하더라..ㅎㅎ
그래서 좀더 크로스 브라우징이 가능한 방법이 없을까?
생각하다가.. Flash 인터페이스를 이용하는건 어떨까 생각해봤다.
아래 링크를 참조하고..
http://kimkijeung.com/entry/IME-Input-Method-Editor
위 링크처럼 가능하다면, 플래시컨테이너 하나 로드해놓고,
인터페이스 함수만들어서, 자바스크립트로 해당 함수를 호출하면
간단히 해결될것같은데..
오늘 집에가서 한번 만들어봐야겠당..ㅋ
반대로, FF에서 한글을 입력 안하게 하는 방법도 있을수 있겠다
편법이지만..
http://blog.hooriza.com/1049
Trackback URL : http://miconblog.com/tc/sohn/trackback/489
+-----------------------------------------------------+
| text/javascript | text/ecmascript |
| text/javascript1.0 | text/javascript1.1 |
| text/javascript1.2 | text/javascript1.3 |
| text/javascript1.4 | text/javascript1.5 |
| text/jscript | text/livescript |
| text/x-javascript | text/x-ecmascript |
| application/x-javascript | application/x-ecmascript |
| application/javascript | application/ecmascript |
+-----------------------------------------------------+
Trackback URL : http://miconblog.com/tc/sohn/trackback/399
이 부분을 번역할까 말까 한참을 고민했다.
대략 A4 한장 분량의 번역작업이 대충 2시간이 걸렸기 때문이다.
머이리 오래 걸려? 라고 묻는자에게 말하고 싶다.. 당신이 해봐~!! -_-
내가 알고 번역하는 것과,.. 모르고 번역한 것은 천지 차이다.
주위에 한글 번역서만 봐도 이건 금방 안다. 대부분이 아마도 원문을 보라고 권할 것이다.
나도 그렇다. 내가 모 취미반 공부반으로 번역은 하고 있지만, 원문을 꼭 다시 볼것을 권하는 바이다. 분명 이렇게 이야기 해도 안보는 사람들을 위해, 최대한 메끄럽게 번역할려고 노력중이다.
왜냐면, 나도 나름 영문꽈 학위 받은 남자기 때문에.. ㅋㅋㅋ
작년말에, 영한번역 수업을 들어놓은게 참 많이 도움이 되는거 같다..
여튼 각설하고,.. 시작해보자!!
원문 번역: http://www.jibbering.com/faq/faq_notes/closures.html
A4 용지로 출력하면, 15페이지중에 7번째 페이지가 되겠다!!
자동으로 일어나는 가비지 콜렉션
ECMA 스크립트는 자동으로 일어나는 가비지 콜렉션을 사용한다. ECMA 262 스펙 명세서에는 어떻게 가비지 콜렉션이 작동하는지에 대한 자세한 정의는 없지만, 일반적으로 "어떤 객체가 자신을 가르키는 참조자가 없을 경우에 그 객체는 가비지 콜렉터에 의해 가비지 콜렉션될수 있다." 라는것이 일반적인 내용이다. 그러나 가비지 콜럭터에 의해 어느순간 콜렉션이 실제로 일어나는지 일어나지 않는지는 장담할수 없다.
(역주) 첫단락 해석이 이상해 의역을 많이 했다. 그리고 현재 ECMA 스펙을 확인중이다. 실제로 구현에 대한 아이디어가 있는지 없는지.. 확인 해봐야겠다..ㅋㅋㅋ
ECMA 스펙을 한창 보았다. 물론 처음부터 끝까지 보고 있는건 아니고, 필요한 부분만 참조해서 봤다. 그런데.. 오호라~ +_+_+_+ 스펙문서가 역시나 도움이 많이 됐다. 몰랐던 구현에 관한 아이디어가 너무나 많다. 물론 가비지 콜렉션에 대한 내용은 없었다. ㅋㅋㅋ
스펙문서를 보고, 처음에 이 문서 번역을 하면서 난해했던 부분이 상당부분 이해가 되고 있다 +_+_+ 이것도 차차 정리해둬야겠다.. 아~ 고수의 길은 멀고도 험하구낭..여튼 이어서~!!
클로져 만들기
클로져는 함수 객체가 리턴 되면서 형성되는데, 여기에는 2가지 조건이 있다.
먼저, 중첩된 함수가 다른 객체의 프로퍼티로 참조되거나 아니면, 전역변수나 전역적으로 접근 가능한 객체 혹은 외부 함수(중첩된 함수를 감싸는 함수)의 인자로써 넘겨지는 객체로 참조 되어질때, 클로져가 만들어진다. 아래 예제를 보자.
function exampleClosureForm(arg1, arg2){
var localVar = 8;
function exampleReturned(innerArg){
return ((arg1 + arg2)/(innerArg + localVar));
}
/* return a reference to the inner function defined as -
exampleReturned -:-
*/
return exampleReturned;
}
var globalVar = exampleClosureForm(2, 4);
위에 exampleClosureForm 실행문맥 안에서 생성된 함수 객체는 가비지 콜렉션 되지 않는다. 그 이유는 전역변수에 의해 참조 되고, 여전히 접근 가능하기 때문이다. 또한, globalVar(n) 과 같은 형식으로 호출되어 실행할수도 있다.
하지만 위에 경우는 새로 생성된 실행 문맥 안에서 만들어진 함수객체가 globalVar 변수에 의해 참조되고 있고, 그 함수 객체의 [[scope]] 프로퍼티가 스코프 체인의 Activation/Variable 객체를 가르키고 있기 때문에 약간 복잡한 경우에 해당한다. 즉, 새로 생성된 exampleClosureForm 실행 문맥의 스코프 체인의 Activation/Variable 객체 역시 가비지 콜렉션이 되지 않는다.
현재 클로져가 형성되었고,위에 중첩된 내부함수 객체는 자유로운 변수들( 역주: free variables가 무엇을 의미하는지 정확히 알수 없으나, 다른 일반 변수들 보다 제약이 적다는 의미로 해석된다. 그런데 왜 저럽게 free variables라고 표현했는지 아직은 모르겠다. )과 스코프 체인에 있는 Activation/Variable 객체를 가진다.
그 Activation/Variable 객체는 globalVar 변수에 의해 참조되는 함수 객체의 [[scope]] 프로퍼티에 의해 참조되어 묵여 있는 상황이다. 그래서 이 Activation/Variable 객체는 그것의 프로퍼티의 값들이 그대로 보존된 상태로 있다. 중첩된 함수를 호출하는 실행문맥 안에서의 스코프에 대한 해석은 식별자로 해석을 한다. 즉, Activation/Variable 객체의 프로퍼티들이 식별자가 된다는 의미다. 그리고 이것은 여전히 set 과 put 두 가지를 모두 수행할수 있고, 실행문맥이 끝나더라도 여전히 존재하게 된다. 왜냐?.. 클로져로 묵여있는 상황이기 때문이다.
위 예제에서 외부 함수(내부 함수를 감싸는)가 리턴될때, Activation/Variable 객체는 공식적인 파라메타 그리고 중첩 함수 정의와 지역 변수로써 대표되는 상태를 가지고 있다. 즉, Activation/Variable 객체의 arg1 프로퍼티는 값 2 를 가지고 있고, arg2 프로퍼티는 값 4를 그리고 localVar 변수는 값 8을 그리고 exampleReturned 프로퍼티는 중첩된 내부 함수 객체를 가르키는 참조자를 가지고 있다. (앞으로 요 Activation/Variable 객체를 편의상 "ActOuter1" 이라고 부를것이다.)
만약에 exampleClosureForm 함수가 아래처럼 다시 호출되면,
var secondGlobalVar = exampleClosureForm(12, 3);새로운 Activation 객체를 가지는 실행문맥이 만들어지고, 새로운 함수 객체가 리턴된다. 그 리턴되는 함수 객체의 [[scope]] 프로퍼티는 바로 이 두번째 실행문맥 안의 Activation 객체를 참조한다. 여기서 이 Activation 객체의 arg1 프로퍼티는 12, arg2 는 프로퍼티는 3를 갖는다. ( 편의상 앞으로 요 Actiovation 객체를 "ActOuter2" 라고 부를 것이다. )
function callLater(paramA, paramB, paramC){Example 2: Associating Functions with Object Instance Methods (객체 인스턴스의 메소드를 갖는 연관 함수)
/*
함수 표현식을 갖는 익명 내부 함수를 만들고 이것을 참조자로 리턴한다.
*/
return (function(){
/* 이 내부 함수는 setTimeout 과 함께 실행 되어진다.
그리고 이분이 실행되어 질때, 이것은 읽을수 있고, 수행되고,
파라메타들을 외부 함수에 넘겨준다.
*/
paramA[paramB] = paramC;
});
}
...
/*
함수를 호출한다. 이 함수는 실행문맥안에서 생성된 내부 함수 객체를 가르키는 참조자를 리턴해줄것이다. 넘겨준 파라메타들은 결과적으로 외부함수의 인자로 실행될때, 내부함수가 사용할것이다. 내부 함수객체를 가르키는 리턴된 참조자는 지역변수에 할당된다.
*/
var functRef = callLater(elStyle, "display", "none");
/*
setTimeout 함수를 호출하고, 첫번째 인자로 할당한 내부 함수를 참조자를 functRef 변수로 넘겨준다.
*/
hideMenu=setTimeout(functRef, 500);
/*
이벤트 핸들러와 연관된 객체 인스턴스의 일반적인 함수.
내부 함수는 이벤트 핸들러로써 사용되는 내부함수를 리턴 한다.
객체 인스턴스는 obj 파라메타를 넘겨받는다. 그리고 그 메소드 이름은
객체가 methodName 파라메타를 넘겨줄때 호출된다.
*/
function associateObjWithEvent(obj, methodName){
/*
그 리턴된 내부 함수는 DOM 엘리먼트를 위한 이벤트 핸들러로 사용된다.
*/
return (function(e){
/* The event object that will have been parsed as the - e -
parameter on DOM standard browsers is normalised to the IE
event object if it has not been passed as an argument to the
event handling inner function:-
*/
e = e||window.event;
/* The event handler calls a method of the object - obj - with
the name held in the string - methodName - passing the now
normalised event object and a reference to the element to
which the event handler has been assigned using the - this -
(which works because the inner function is executed as a
method of that element because it has been assigned as an
event handler):-
*/
return obj[methodName](e, this);
});
}
/* This constructor function creates objects that associates themselves
with DOM elements whose IDs are passed to the constructor as a
string. The object instances want to arrange than when the
corresponding element triggers onclick, onmouseover and onmouseout
events corresponding methods are called on their object instance.
*/
function DhtmlObject(elementId){
/* A function is called that retrieves a reference to the DOM
element (or null if it cannot be found) with the ID of the
required element passed as its argument. The returned value
is assigned to the local variable - el -:-
*/
var el = getElementWithId(elementId);
/* The value of - el - is internally type-converted to boolean for
the - if - statement so that if it refers to an object the
result will be true, and if it is null the result false. So that
the following block is only executed if the - el - variable
refers to a DOM element:-
*/
if(el){
/* To assign a function as the element's event handler this
object calls the - associateObjWithEvent - function
specifying itself (with the - this - keyword) as the object
on which a method is to be called and providing the name of
the method that is to be called. The - associateObjWithEvent
- function will return a reference to an inner function that
is assigned to the event handler of the DOM element. That
inner function will call the required method on the
javascript object when it is executed in response to
events:-
*/
el.onclick = associateObjWithEvent(this, "doOnClick");
el.onmouseover = associateObjWithEvent(this, "doMouseOver");
el.onmouseout = associateObjWithEvent(this, "doMouseOut");
...
}
}
DhtmlObject.prototype.doOnClick = function(event, element){
... // doOnClick method body.
}
DhtmlObject.prototype.doMouseOver = function(event, element){
... // doMouseOver method body.
}
DhtmlObject.prototype.doMouseOut = function(event, element){
... // doMouseOut method body.
}
그래서 이 DhtmlObject의 인스턴스는 내부적으로 어떻게 다른 코드에 의해 쓰이고, 전역 네임스페이스와 다른 DHtmlObject 인스턴스와의 충돌 신경쓰지 않고도, 스스로 DOM 엘리먼트를 연관시킬수 있다. Trackback URL : http://miconblog.com/tc/sohn/trackback/390
Trackback URL : http://miconblog.com/tc/sohn/trackback/387
function exampleFunction(formalParameter) {위 함수는 전역 실행 문맥안에서 변수 인스턴스화 과정을 통해 함수 객체로 생성된다.
.... // function body code
}
var exampleFuncRef = function() {위와 같은 경우를 제외하고 전역 객체의 이름있는 프로퍼티들은 전역 실행 문맥에서 변수 인스턴스화 과정을 거치면서 생성되어 진다. 하지만 위 예제의 함수 객체는 인스턴스화 과정에서 생성되는것이 아니라 변수에 할당된 함수 표현식이 평가 될때 생성된다. 그러므로 인스턴스화 과정을 거칠때 위 예제의 함수는 전역 객체에 의해 참조 되지 않는다.
... // function body code
}
function exampleOuterFunction (formalParameter) {밖에 선언된 함수의 객체는 전역 실행 문맥의 변수 인스턴스화 과정에서 만들어지기 때문에 그 함수(exampleOuterFunction) 객체의[[scope]] 프로퍼티는 전역객체만을 가지는 스코프체인을 가르키게 된다.
function exampleInnerFunctionDec() {
... // inner function body
}
.... // the rest of the outer function body.
}
exampleOuterFunction(5);
/* 전역 변수 y를 만들고 그것이 하나의 객체를 참조한다. */exampleFuncWith 함수가 호출되어 질때, 그 결과의 실행 문맥은 그 실행문맥 안의 Activation 객체에서 전역 변수까지 참조하는 스코프 체인을 가진다. 그리고 with문을 수행할때 전역 변수 y가 참조하는 객체를 이 스코프 체인 맨 앞에 추가한다.
var y = {x:5}; // x 프로퍼티를 가지는 객체 리터럴
function exampleFuncWith(){
var z;
/* 전역 변수에 의해 참조 되는 객체를 y에 추가하고 그것을 스코프 체인 앞에 둔다. */
with(y){
/* 함수 객체를 생성하기 위해 함수식을 평가하고, 지역 변수 z를 함수 객체의 참조로 할당한다.
*/
z = function(){
... // inner function expression body;
}
}
...
}
/* execute the - exampleFuncWith - function:- */
exampleFuncWith();
Trackback URL : http://miconblog.com/tc/sohn/trackback/385
원문 출처 : http://www.jibbering.com/faq/faq_notes/closures.html
평소에 일반적인 C,C++,Java,C# 이딴 언어를 주로 사용하다 자바스크립트와 같은 스크립트 언어를 조금만 하다보면, 금방 궁금증이 늘어난다.
과연.. 요놈들은 왜? 이렇게 작동하는걸까? 라는 좀 원초적인 질문이다.
어제 오늘 클로저라는 놈을 제대로 이해하기위해, 각종 아티클들을 찾아보다가..
괜찮은 아티클을 발견하고, 지금 번역은 아니고.. 그냥 해석해서 이해하는 중이다.
사실 클로저라는 놈을 이해하기위해선, 자바스크립트 내부적으로 작동하는 매커니즘을 이해할 필요가 있다..
이름하야, Indentifier Resolution, Execution Contexts, Scope Chains, Property Chain 같은 용어와 내부 매커니즘을 이해해야 한다는 얘기다.
오늘은 그중에서 실행문맥(Execution Contexts)에 대해서 정리해보자.
위에 원문을 A4로 출력하면, 대략 4페이지에 나오는 내용이다.
실행문맥은 ECMAScript 스펙에서 정의 된대로 추상적인 개념이고, 요 스팩을 구현하기 위해서 요구되는 지침정도라고 생각해보면 되겠다. 하지만 스펙에는 어떻게 구현하라는 이야기는 없으므로, 대충 개념만이라도 이해하자.
모든 자바스크립트 코드의 실행은 실행문맥안에서 이루어 진다. 전역 코드가 실행될때는 전역실행문맥이라고 불리는 곳에서 실행된다. 그리고 그 전역실행 문맥 안에 존재하는 각각의 function 들은 그 펑션마다 고유의 실행 문맥이 만들어지고 그 안에서 실행이 된다. eval 펑션은 예외다.
자바스크립트 펑션이 호출되면, 실행문맥안으로 들어가고 그안에서 새로운 펑션이 호출되면, 새로운 실행문맥을 만들고, 그 실행문맥 안으로 들어간다. 그리고 값이 리턴되면, 본래 호출되었던 펑션으로 복귀를 하게 되고, 이값도 리턴이 되면, 실행문맥은 사라진다.
결국 실행문맥이라는 것은 우리가 흔히 메모리 구조를 그릴때 그리는 스택구조와 비슷하다고 보면 되겠다.
일반 실행 문맥
실행문맥이 생성될때, 많은 일들이 순차적으로 일어난다.
1. Activation 객체 생성
먼저, 펑션의 실행문맥안에서 특별한 매커니즘을 갖는 Activation 이라는 객체를 만든다. 이 Activation 객체는 결과적으로 이름이 있는 프로퍼티에 접근할수 있으므로, 일반적인 객체라고 봐도 무방하다. 하지만, 일반 객체들이 모두 가지고 있는 프로토타입(prototype)을 가지고 있지 않고, 자바스크립트 코드에 의해서 직접적으로 참조되지 않는다.
2. arguments 객체 생성
다음으로 배열과 비슷하게 index를 가지는 Arguments 객체를 생성한다. 이 객체는 length(호출자가 넘겨주는 인자의 갯수)와 callee(실행중인 함수 객체-재귀를 위해 필요하다) 프로퍼티도 갖는다.
그리고 앞서 만든 Activation 객체에 "arguments"라는 이름의 프로퍼티가 만들어지고, 이 arguments객체를 참조할수 있도록 할당(assign)된다.
3. scope 할당
다음으로, 실행문맥은 Scope를 할당(assign)한다. 스코프는 객체들의 리스트로 구성된다. 흔히들 스코프 체인이라고 이야기한다. 한편 각 펑션 객체는 내부적인 [[scope]] 프로퍼티를 갖고 있는데, 그 [[scope]] 프로퍼티 역시 객체들의 리스트로 구성된다.
실행문맥에 할당된 스코프는 맨 앞에 Actiovation객체를 넣고, 호출된 본 함수 객체의 [[scope]] 프로퍼티가 참조하는 리스트들을 함께 구성한다.
4. 변수 인스턴스화 과정수행
다음으로, ECMA 262에서 "Variable" 객체로 언급한 객체들을 사용해서 변수의 인스턴스화("variable instantiation") 과정이 일어난다. Activation 객체 또한 Variable 객체로써 사용된다. (결국 Activation 객체와 Variable 객체는 사실상 같은 객체다. 아주 중요하니 체크하기 바람!!)
함수 표현식에서 선언된 공식적인 파라메타들을 식별자로 Activation 객체의 프로퍼티로 생성하고, 호출자로 부터 넘어온 인자값은 그 프로퍼티들의 값으로 한다. 인자가 넘어오지 않은 프로퍼티는 그 값으로는 undefined 할당이 된다.
함수 선언에서 사용된 함수 이름은 그 이름으로 함수 객체를 만들고 Variable 객체(이름은 다르게 표현하지만 결국 Activation 객체를 말한다)의 프로퍼티로 생성한다.변수 인스턴스화의 마지막 과정은 함수 안에서 지역변수로 선언된 모든 변수들을 Variable 객체의 프로퍼티로 생성하면서 마무리 짓는다.
변수 인스턴스화 과정에서 지역 변수로 생성된 프로퍼티들은 모두 undefined 값으로 초기화된다. 실질적인 값 초기화 과정은 함수 내부 코드가 실행될때 비로서 값이 정해진다는것을 잊지말자!
arguments 프로퍼티를 가지는 Activation 객체와 지역 변수로 쓰이는 정해진 이름의 프로퍼티들을 가지는 Valiable 객체는 결국 서로 같은 객체다. 그리고 식별자 arguments 가 마치 지역변수로써 쓰일수 있도록 허가되어진다.
5. this 키워드 값 할당
마지막으로 this 키워드 값이 할당된다. 만일 this가 어떤 객체를 참조하도록 할당이 되면, 프로퍼티 접근 연산자를 통해서 그 this 키워드가 가르키는 객체의 프로퍼티들을 참조 한다.
즉, this.(프로퍼티 이름) 이딴 식으로 참조할수 있게 되고, this 에 null 값이 할당되면, 이 this 키워드는 전역 객체(window)를 참조하게 될것이다.
전역 실행 문맥
전역 실행 문맥은 arguments 가 없기 때문에 정의된 Activation 객체를 가질필요가 없다는 것이 약간 다르다. 하지만 스코프는 필요로 한다. 전역 실행 문맥의 스코프 체인은 오직 전역 객체 하나만을 가르킨다.
역주) 코드에서 선언된 전역변수는 모두 이 전역객체의 프로퍼티로 들어가기 때문에 사실상 전역객체 하나만 가지고 있는 꼴이 된다.
일반적인 최상위 레벨의 함수 선언들은 전역 실행 문맥의 내부 함수 들로써, 변수 인스턴화 과정을 거친다. 즉, 이 변수 인스턴화 과정을 거치게 되므로, 결론적으로 이 함수들은 전역 객체의 프로퍼티로써 존재하게 된다. 그리고 마지막으로 전역객체는 this 객체를 통해서 참조 될수 있다.
Trackback URL : http://miconblog.com/tc/sohn/trackback/384