Scala의 foldLeft, foldRight에 대한 설명을 들으며 이런 생각이 들었다.


foldLeft, foldRight의 차이점을 바탕으로 재귀호출의 형식을 구분하면,

  1. 현재 stack에서 계산한 결과를 다음 재귀호출의 인자로 사용하는 것.
  2. 재귀호출의 결과를 현재 stack에서 수행해야 할 계산의 인자로 사용하는 것.
  3. 1과 2를 모두를 조합한 것.


tail-recursion 가능 여부는

  • 1을 잘 다듬으면 tail-recursion으로 만들 수 있지만
  • 2와 3은 복귀해야 할 stack이 존재하므로 tail-recursion으로 만들 수 없다.


15년 만에 재귀호출을 조금 이해한 느낌이다.




Posted by 배트
,

'learnyounode' is a set of self-guided workshops. It is installed easily via npm and the content is also so great.


I'm new to Node.js. This is a wonderful entry point to get involved into node world!


Even though I just finished this practice and haven't had much information about how to utilize node, I'm just gonna proceed to build a simple API server. I'm so excited with expecting how simple the code will be!


To get information about this practice, check this:

https://github.com/workshopper/learnyounode


My practice code is here:

https://github.com/batt842/learnyounode

Posted by 배트
,

Proxy나 LB처럼 L7 스위칭을 하는 장치를 통과한 HTTP 헤더는 host가 L7 스위치의 주소로 덮어써진다.

L7 스위치를 지날 때마다 이전 주소는 X-FORWARDED-FOR에 차곡차곡 기록되는데,

최초 HTTP request를 한 host의 주소를 알기 위해서는 이 정보를 이용해야 한다.

아래는 Java로 구현된 Controller의 소스 코드이다.


public final class HttpUtils {

    private static final String HEADER_X_FORWARDED_FOR = "X-FORWARDED-FOR";


    /**

     * Returns the original host's IP address of the HTTP request.

     * It ignores any L7 switches.

     * 

     * @param request

     * @return

     */

    public static String getFirstRemoteAddr(HttpServletRequest request) {

        String remoteAddr = request.getRemoteAddr();

        String x;

        if ((x = request.getHeader(HEADER_X_FORWARDED_FOR)) != null) {

            remoteAddr = x;

            int idx = remoteAddr.indexOf(',');

            if (idx > -1) {

                remoteAddr = remoteAddr.substring(0, idx);

            }

        }

        return remoteAddr;

    }

}



출처: http://johannburkard.de/blog/programming/java/x-forwarded-for-http-header.html

Posted by 배트
,

모든 테스트는 BORANET(by LGU+) 망의 PC에서 수행.



CloudPing을 이용한 Latency 테스트


US-East (Virginia)

234 ms

US-West (California)

141 ms

US-West (Oregon)

158 ms

Europe (Ireland)

298 ms

Asia Pacific (Singapore)

202 ms

Asia Pacific (Sydney)

152 ms

Asia Pacific (Japan)

67 ms

South America (Brazil)

341 ms

참고: http://www.cloudping.info/




EC2 업/다운로드 Throughput 테스트


US-West(Oregon), Asia-Pacific(Singapore), Asia-Pacific(Japan)의 EC2 인스턴스가 대상.

업로드는 rsync, 다운로드는 wget을 이용.


결과:

US-West(Oregon), Asia-Pacific(Singapore):

업/다운로드 모두 600~1200 KB/s의 속도를 보임.

동시 업/다운로드에서 속도 저하 없음.

긴 Latency로 인한 다운로드 속도의 변화폭은 그리 크지 않음.


Asia-Pacific(Japan):

1.6~1.8 MB/s 의 양호한 속도.



비고:

1. Olleh uCloud의 VM에서 테스트를 한 결과, 3 MB/s 쯤에서 다운로드가 완료되었는데 속도는 계속 상승 중이었음. 데이타 센터의 기간망이 빠르긴 하겠지만, 그래도 KT 망에서 더 빠른 속도를 낼 것이라 희망적으로 예상.



S3 업로드 Throughput 테스트


결과#1 US-West(Oregon):

200 ~ 350 KB/s 정도로 조금 변동폭 있음.

긴 Latency로 인한 다운로드 속도의 변화폭은 그리 크지 않음.


결과#2 Asia-Pacific(Singapore)

250 KB/s 정도로 균일함.


결과#3 Asia-Pacific(Japan)

최대 750 KB/s 까지 상승했지만 대체로 600 KB/s 안팎 수준에서 안정.




비고:

1. 모든 업/다운로드가 10 KB/s 수준의 속도에서 시작하는 것으로 보아, 초기 TCP Window 크기가 작은 것으로 추정됨.


Posted by 배트
,

이런건 보관해놓자.





Posted by 배트
,
Web Server의 간단한 스트레스 테스트를 하려고 하는데,
하늘의 별만큼 많은 게 테스트 툴이라... 

MS Web Application Stress Tool은 일정 버전 이상의 윈도우에서 동작을 안하고,
JMeter는 쉽고, 많이 쓰이지만 장기가 테스트를 돌리면 뻗는 문제가 있다.
WebLoad를 사용해보려 한다.

아래 링크에 가면 별처럼 많은 테스트 툴들을 볼 수 있다.
http://www.opensourcetesting.org/performance.php  
Posted by 배트
,
Apartment(STA)와 Single(Legacy Single)의 차이점을 몰라서 엄청 헤매던 끝에 해답을 준 아티클입니다.
Windows 서버에서 COM의 동접이나 성능에 관련된 문제를 겪으시는 분들을 읽어보세요.
이걸로 해!결!

Part1
http://www.codeproject.com/Articles/9190/Understanding-The-COM-Single-Threaded-Apartment-Pa 


Part2
http://www.codeproject.com/Articles/9506/Understanding-The-COM-Single-Threaded-Apartment-Pa  
Posted by 배트
,
This code is based on Apache common library.
If you are able to use the library, I recommend it. :-)

private boolean contentEquals(File file1, File file2) throws IOException {

    boolean file1Exists = file1.exists();

    if (file1Exists != file2.exists()) {

        return false;

    }


    if (!file1Exists) {

        // two not existing files are equal

        return true;

    }


    if (file1.isDirectory() || file2.isDirectory()) {

        // don't want to compare directory contents

        throw new IOException("Can't compare directories, only files");

    }


    if (file1.length() != file2.length()) {

        // lengths differ, cannot be equal

        return false;

    }


    if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {

        // same file

        return true;

    }


    FileInputStream fileStream1 = new FileInputStream(file1);

    FileInputStream fileStream2 = new FileInputStream(file2);


    BufferedInputStream bufferedStream1 = new BufferedInputStream(fileStream1);

    BufferedInputStream bufferedStream2 = new BufferedInputStream(fileStream2);


    int ch = bufferedStream1.read();

    while (-1 != ch) {

        int ch2 = bufferedStream2.read();

        if (ch != ch2) {

            return false;

        }

        ch = bufferedStream1.read();

    }


    int ch2 = bufferedStream2.read();


    bufferedStream1.close();

    bufferedStream2.close();


    return (ch2 == -1);

}



Posted by 배트
,
조금 재미있긴 했는데 업무 시간에 너무 딴짓 했네.

<html>

<head> 


<META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=euc-kr"> 


<title>Layer Test</title>


<script language="JavaScript"> 


var newArticleDivId = "write_article_layer";

var newArticleUrl = "http://www.naver.com/";

var minimumMargine = 50;

var maximumWidth = 800;


/*

 * openLayeredDialog

 * 레이어에 떠 있는 iFrame을 웹 페이지에 표시한다.

 */

function openLayeredDialog() {

    // 배경이 되는 반투명 레이어를 생성한다.

    var div1 = document.createElement("DIV");

    div1.id = newArticleUrl;

    div1.onclick = function () {closeLayeredDialog(false);};

    div1.style.position = "absolute";

    div1.style.height = "100%";

    div1.style.width = "100%";

    div1.style.top = "0";

    div1.style.left = "0";

    div1.style.background = "#000000";

    div1.style.opacity = "0.6";

    div1.style.filter = "alpha(opacity=60)";

    

    // iFrame을 담는 레이어를 생성한다.

    var div2 = document.createElement("DIV");

    div2.id = newArticleDivId + "_inner";

    div2.style.position = "absolute";

    div2.style.background = "#ffffff";

    

    // iFrame을 생성한다.

    var iframe1 = document.createElement("IFRAME");

    iframe1.src = newArticleUrl;

    iframe1.frameborder = "0";

    iframe1.style.height = "100%";

    iframe1.style.width = "100%";

    

    // 앞서 생성한 Element들을 웹 페이지에 추가한다.

    div2.appendChild(iframe1);

    document.body.appendChild(div1);

    document.body.appendChild(div2);

    

    // 레이어의 크기를 조정한다.

    adjustmentLayeredDialog();

    

    // 웹브라우저의 크기를 조절할 때 발생하는 이벤트의 핸들러를 등록한다.

    window.onresize = function(event) {adjustmentLayeredDialog();};

}


/*

 * closeLayeredDialog

 * 레이어를 제거한다.

 * 인자 normalClose가 true라면 Confirm 대화 창을 표시한다.

 * 인자 normalClose가 false라면 Confirm 대화 창을 표시하지 않는다.

 */

function closeLayeredDialog(normalClose) {

    // Confirm 대화 창을 표시한다.

    if (!normalClose) {

        willClose = confirm("이 페이지에서 나가면 작성하던 내용들은 저장되지 않습니다.\n정말 나가겠습니까?");

    } else {

        willClose = true;

    }

    

    // 레이어를 제거한다.

    if (willClose) {

        var child_background = document.getElementById(newArticleDivId);

        var child_inner = document.getElementById(newArticleDivId + "_inner");

        

        if (child_background) {

            document.body.removeChild(child_background);

        }

        if (child_inner) {

            document.body.removeChild(child_inner);

        }

        

        // 레이어를 제거하며 웹브라우저의 크기를 조절할 때 발생하는 이벤트의 핸들러도 제거한다.

        window.onresize = null;

    }

}


/*

 * adjustmentLayeredDialog

 * 레이어를 크기와 위치를 조정한다.

 */

function adjustmentLayeredDialog() {

    var child_inner = document.getElementById(newArticleDivId + "_inner");

    if (child_inner) {

        var clientHeight = document.body.clientHeight;

        var clientWidth = document.body.clientWidth;

        var top = minimumMargine;
        var left = 0;

       

        var height = clientHeight - minimumMargine * 2;

        var width = clientWidth - minimumMargine * 2;

        

        if (width > maximumWidth) {

            width = maximumWidth;

        }

            

        left = (clientWidth - width) / 2;

    

        child_inner.style.height = height;

        child_inner.style.width = width;

        child_inner.style.top = top;

        child_inner.style.left = left;

    }

}


</script> 


</head> 


<body>


<a href="javascript:openLayeredDialog();">레이어 보이기</a>


</body>

</html>

 
Posted by 배트
,
성능은 보장 못해도 완전 심플하다 ㅋㅋㅋ

출처: Simple Implementation of Wildcard (*) Text Matching using Java
http://www.adarshr.com/papers/wildcard

/**
 * Performs a wildcard matching for the text and pattern 
 * provided.
 * 
 * @param text the text to be tested for matches.
 * 
 * @param pattern the pattern to be matched for.
 * This can contain the wildcard character '*' (asterisk).
 * 
 * @return <tt>true</tt> if a match is found, <tt>false</tt> 
 * otherwise.
 */

public static boolean wildCardMatch(String text, String pattern)
{
    // Create the cards by splitting using a RegEx. If more speed 
    // is desired, a simpler character based splitting can be done.
    String [] cards = pattern.split("\\*");

    // Iterate over the cards.
    for (String card : cards)
    {
        int idx = text.indexOf(card);
        
        // Card not detected in the text.
        if(idx == -1)
        {
            return false;
        }
        
        // Move ahead, towards the right of the text.
        text = text.substring(idx + card.length());
    }
    
    return true;
}

Posted by 배트
,