tag:blogger.com,1999:blog-45675513704359548902024-02-07T04:59:04.898-08:00Stranger in LA끄적끄적 Daily life in USCromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.comBlogger58125tag:blogger.com,1999:blog-4567551370435954890.post-2689076848275580382015-07-27T16:23:00.001-07:002015-07-27T16:23:44.902-07:00네트워크 퍼포먼스 튜닝 팁<div>
Intel NIC 퍼포먼스 튜닝에 관한 팁</div>
<div>
<br /></div>
<div>
Intel I/OAT BIOS 설정</div>
<ol>
<li style="display: inline; list-style: none;"><ol>
<li>Intel QuickData Technology : 송수신에 관계된 데이터 전송을 CPU가 아닌 Chipset 을 통해 전담하도록 하여 퍼포먼스를 향상시킨다.</li>
<li>Direct Cache Access (DCA) : NIC로 하여금 데이터를 바로 CPU캐쉬로 전송할 수 있도록 하여 캐시 미스를 줄이고 어플리케이션 반응속도를 향상 시킨다</li>
<li>Extended Message Signaled Interrupts (MSI-X) : I/O 인터럽트를 다수의 CPU와 CPU 코어로 분매하여 CPU 사용율을 높이고 어플리케이션 퍼포먼스를 향상 시킨다.</li>
<li>Receive Side Coalescing (RSC) : 하나의 TCP/IP 데이터 흐름에서의 작은 데이터 패킷을 결합하여 큰 패킷을 만들어 주어 패킷당 프로세싱 비용을 줄인다.</li>
<li>Low Latency Interrupts : 인터럽트 간격을 포트 번호 혹은 패킷 사이즈에 따른 데이터의 레이턴시 민감도에 따라 튜닝하여 프로세싱 효율을 향상시킨다.</li>
</ol>
</li>
</ol>
<div>
그외 퍼포먼스 튜닝 옵션</div>
<ol>
<li>수신 송신 버퍼 사이즈 최대값 설정 : 2048 byte로 버퍼 사이즈를 최대값을 설정한다. 이 경우 호스트의 메모리를 더 많이 소비하게 되는 단점이 있다. 네트워크를 조사하여 Zero-window 상황이 많이 발생한다면 어느 쪽이든 버퍼를 늘림으로써 상황을 완화 시킬 수 있다.</li>
<li>Interrupt Moderation 옵션 끄기 : 이 기능은 NIC로 하여금 CPU에게 가해지는 인터럽트 수를 제한함으로써 결국 NIC의 CPU 사용량을 줄어들게 만든다. 이 옵션을 끄게 되면 CPU 사용량이 늘어나는 단점은 있으나 패킷이 처리되지 못하고 버퍼에 남아서 CPU 인터럽트를 기다리게 되는 상황을 막아 준다.</li>
<li>Receive Side Scaling : 이 기술은 CPU의 멀티 코어를 활용하여 각 코어로 하여금 TCP 컨넥션을 할당하여 처리하도록 하게 하는 기술이다. 이렇게 함으로써 CPU가 여러개의 TCP 코어를 무작위로 처리할때 보다 캐시 활용율을 높여서 전체적인 성능을 높일 수 있다.</li>
<li>Receive Side Scaling Queue : Receive Side Scaling 기술과 함께 CPU와 NIC사이에 버퍼 공간을 두어 네트워크 성능을 향상시킬 수 있다.</li>
</ol>
<div>
</div>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-24399335473351212382015-02-25T16:23:00.003-08:002015-02-25T16:23:46.153-08:00레고 취미 생활에 빠지게 된 계기작년에 한국에 방문했다가 아는 형들의 뽐뿌를 받아 취미로 레고 수집을 시작하게 되었다. 계기는 그랬다 SF 출장길에서 돌아오는 비행기에서 레고 제품들의 리뷰를 살펴보게 되었고, 그중에서 괜찮아 보이던 펫샵을 집 근처 레고스토에서 장만하게 되었고, 그것을 조립하다가.. 그만 완전히 빠져 버리고 말았다.<br />
<br />
조립을 하면서는 그 디테일함에 반했고,<br />
조립을 끝내고 나서 느껴지는 성취감과,<br />
전시품으로써의 가치를 통해 완전히 레고빠가 되었다.<br />
<br />
사실 그전까지 레고라고 하면 어렸을적 듀플로를 가지고 놀던 기억밖에 없었기에 얼마나 대단할까 생각했었다.<br />
<br />
조그마한 브릭들이 점점 쌓아 올려져가며 형상을 이루고 그것이 아름다운 자태를 뽐내며 완성이 되었을때 느껴지는 성취감이란 어마어마 한 것이었고. 도무지 빠져들지 않을 수가 없었다.<br />
<br />
그 이후로는 또 여러 레고 동호회에서 활동하며 다양한 제품들의 리뷰를 보게 되었고 그렇게 한개 두개 사모으다 보니 집안 빈 구석은 온통 레고로 가득찬 집이 되었다.<br />
<br />
다행이 최근에 이사를 와서 조금 더 공간이 생겼지만 또 곧 가득차 버리지 않을지..<br />
스스로 내가 이렇게 수집욕이 있는 사람인지 몰랐다. 아니면 레고가 사람을 이렇게 만드는지도 모르겠다.<br />
<br />
아무튼 나이들어 생긴 취미가 하나 더 늘어 좋다. 점점 지갑이 비어가는것만 제외하면 와이프도 좋아하고 애기도 좋아하고. 이 얼마나 좋은 취미인가.<br />
<br />
그렇게 취미 생활을 영위하다가 개발자로써의 본능에 이끌려 MyBrickDeal이라는 사이트를 창조하게 되었다.<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-48239812562718445572014-12-16T18:18:00.000-08:002014-12-16T18:18:28.269-08:00Install SBT on Amazon linuxSimple!<br />
<br />
> sudo yum install -y https://dl.bintray.com/sbt/rpm/sbt-0.13.7.rpmCromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-4644837681205682542014-09-09T21:34:00.003-07:002014-09-09T21:34:33.241-07:00애플 와치 실제 사용 영상 모음<p>아.. 프로모션 영상은 정말 이뻐 보였는데 실제 모습은 많이 두꺼워 보이긴 하네요.</p>
<p><br /></p>
<p><br /></p>
<iframe width="640" height="360" src="//www.youtube.com/embed/PMtNQZKEBU8" frameborder="0" allowfullscreen=""></iframe><br />
<iframe width="640" height="360" src="//www.youtube.com/embed/Hn8jj9KuKDc" frameborder="0" allowfullscreen=""></iframe><br />
<iframe width="640" height="360" src="//www.youtube.com/embed/-IUiNbl_YbQ" frameborder="0" allowfullscreen=""></iframe><br />
<iframe width="640" height="360" src="//www.youtube.com/embed/zQ_zlDEyaX4" frameborder="0" allowfullscreen=""></iframe><br />
<iframe width="640" height="360" src="//www.youtube.com/embed/CrMAq7DlxvI" frameborder="0" allowfullscreen=""></iframe><br />
<iframe width="640" height="360" src="//www.youtube.com/embed/Y2SHnvtAtxs" frameborder="0" allowfullscreen=""></iframe><br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-34457867997714895542014-09-09T21:26:00.000-07:002014-09-09T21:26:31.094-07:00아이폰 6, 6 플러스 실제 사용 영상 모음난 이뻐 보이는데, 왜 이렇게 온라인에서 많이 까이는지 모르겠네. 얼른 집앞에 애플 스토어 찾아가서 직접 만져 보고 싶다.
<br/>
<iframe width="640" height="360" src="//www.youtube.com/embed/nfNeEsTeKvw" frameborder="0" allowfullscreen></iframe>
<br/>
<iframe width="640" height="360" src="//www.youtube.com/embed/-1QmOhDXwE8" frameborder="0" allowfullscreen></iframe>
<br/>
<iframe width="640" height="360" src="//www.youtube.com/embed/ZG10P3uSpLU" frameborder="0" allowfullscreen></iframe>
<br/>Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-27068992990419628702014-09-08T22:48:00.002-07:002014-09-08T22:49:05.116-07:00모든 프로그래머가 알아야 할 Latency 값<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnpsNmbYVCvVxgmmhO7dS2kkVMFZ4eLT2BH5BsDfb2ojxMgKfYwkfHCtI1vvOb2cKZ_TVijmQbrbilbS9eH9ozDnoV-_x7_DeRAZcPgQHMs3m5IDHo42HIRkU624TjQPEXsYhb-be4qQ4/s1600/Screenshot+2014-09-09+14.35.08.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnpsNmbYVCvVxgmmhO7dS2kkVMFZ4eLT2BH5BsDfb2ojxMgKfYwkfHCtI1vvOb2cKZ_TVijmQbrbilbS9eH9ozDnoV-_x7_DeRAZcPgQHMs3m5IDHo42HIRkU624TjQPEXsYhb-be4qQ4/s640/Screenshot+2014-09-09+14.35.08.jpg" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
성능이 관건인 프로그램을 개발할 때 프로그래머는 메모리에 한번 접근하는데 어느 정도의 시간이 소요되는지, 네트웍에서 일정 량의 데이터를 전송하 데 어느 정도 시간이 소요되는지 감을 잡고 개발하는것과 디스크와 메모리의 접근이 어느 정도 차이가 나는지도 모르는 상태로 개발을 하는 것은 천지차이가 난다. </div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
불과 10여년 전만해도 서버 프로그램을 개발할 때 프로그램 라인 한줄 한줄 퍼포먼스를 생각하면서 개발을 했는데 요즘은 하드웨어 비용도 싸졌다고 아예 퍼포먼스 따위 생각하지 않고 개발하는 프로그래머를 종종 볼 수 있는데, 그런 디테일에서 유능한 프로그래머와 평범한 프로그래머의 차이가 나타난다.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
위의 그림은 아래 사이트에서 캡쳐 해온 것인데 슬라이드바를 움직이면 년도별로도 latency의 차이가 남을 볼 수 있다.</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.eecs.berkeley.edu/~rcs/research/interactive_latency.html" target="_blank">http://www.eecs.berkeley.edu/~rcs/research/interactive_latency.html</a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-86294171491136546162014-08-25T16:42:00.003-07:002014-09-08T22:48:49.789-07:00Scala's parallel collections (병렬 콜렉션)에 관한 소회
스칼라 2.9 버전에서 부터 parallel collections가 소개되었다. 그리고 기존에 존재하는 모든 collections을 쉽게 parallel 버전으로 만드는 법도 같이 소개 되었는데 기존의 collection 에 <code>par</code> 함수를 호출하는 것만으로도 쉽게 변환이 가능하다.<br />
예를 들어 순차적인 버전의 아래 내용은<br />
<pre><code>scala> (1 to 5) foreach println
1
2
3
4
5
</code></pre>
병렬 버전을 사용하면 결곽값이 다음과 같이 바뀐다.<br />
<pre><code>scala> (1 to 5).par foreach println
1
4
4
3
5
</code></pre>
(실행 할때 마다 값은 변경 될 수 있다.)<br />
이런 병렬 콜렉션을 사용하면서 얻을 수 있는 이점을 알아 보기 이전에 이 구조가 가진 문제점을 먼저 파악해보도록 하겠다.<br />
<h2>
컨트롤이 가능하지 않다.</h2>
처음에 병렬 컬렉션의 결과를 접했을 때 가장 먼저 알고 싶었던 것은 스레드가 생성이 되어 작업을 처리했다는 것은 명백한데 얼마나 많은 스레드가 이 연산에 관여 되었는지를 알 수 없다는 것은 큰 문제로 보였다. 위의 경우 1부터 5까지 5개의 숫자를 프린트하는 구문인데 이렇게 5개의 아이템을 다루는 경우 5개의 스레드가 생성이 되는 것인지? 만일 1부터 10,000까지를 처리하는 구문이라면 10,000개의 스레드가 생성이 되는 것인지? 불분명하다. 정답은 스레드 풀을 사용한다 인데 그 스레드 풀에는 도대체 몇개의 스레드가 들어 있는 것인지 어느것도 명확하게 드러나는 것이 없다. 만약 스레드 풀에 10개의 스레드가 있는데 11번째 아이템을 처리를 할 순서가 되었다면 그 처리는 블럭이 되는 것인지? 만약 블럭이 되는 구조라면 어떤 것을 먼저 처리하고 어떤 것을 나중에 할지 설정이 가능한가? 에를 들어 아주 오래 걸리는 작업 하나가 빨리 처리되는 다른 여러개의 작업이 시작되지 못하도록 막고 있다면 어떻게 하나?<br />
이러한 컨트롤의 부재가 실제 병렬 프로그래밍에서는 큰 위험요소가 된다. 따라서 이 병렬 컬렉션의 사용을 아주 심플한 위의 예제와 같은 수준 정도의 사용으로 그치고 만다면 병렬 컬렉션을 통해 얻을 수 있는 퍼포먼스의 이득은 아주 미미할 것이다.<br />
<h2>
특효에 대한 환상</h2>
과거 온라인에서 병렬 콜렉션이 동작하지 않는다는 불평들을 몇몇 접할 수 있었는데 그들의 코드를 살펴보면 대부분 알고리즘이 병렬처리가 불가능하게 짜여져 있음을 알 수 있었다. 그리고 그들 조차 그것을 인식하지 못하고 있던가, 아니면 <code>par</code> 함수가 마법과 같이 그것을 병렬적으로 동작하도록 만들어 줄 것이라고 믿고 있었다.<br />
<pre><code>scala> Set(1,2,3,4,5) mkString(" ")
res1: String = 5 1 2 3 4
scala> Set(1,2,3,4,5).par mkString(" ")
res2: String = 5 1 2 3 4
scala> Set(1,2,3,4,5).par mkString(" ")
res3: String = 5 1 2 3 4
scala> (1 to 6).par mkString(" ")
res4: String = 1 2 3 4 5 6
scala> (1 to 6).par mkString(" ")
res5: String = 1 2 3 4 5 6
</code></pre>
<code>par</code> 버전의 예제를 반복하여 실행하여 보아도 결과는 똑같음을 알 수 있다. 뭔가 이상해 보인다. 이번 예제에는 Set 을 사용하였고 Set 내에 들어 있는 아이템의 순서는 상관이 없다고 선언한 것이나 마찬가지인데 그 결과는 항상 똑같음을 볼 수 있다. 그리고 순차적 버전도 마찬가지로 항상 똑같은 결과를 출력한다. 이것은 명백히도 모든 연산이 병렬화되지 않음을 의미한다. (예를 들어 fold 같은 것들) 그러나 그렇게 되어야 할 것 처럼 보인다. 여기서 왜 그렇게 되지 않는지 자세히 설명하지는 않겠다. 그냥 그것이 folds함수나 set, 스칼라의 상속 구조 그리고 mkString함수의 명세에 따라 병렬처리가 불가능하다는 것을 이해하였으면 좋겠다. 그러나 여기서 중요한 점은 병렬 콜렉션에 대한 잘못된 환상이 비 직관적인 결과에 이를 수 있다는 점이다.<br />
<h2>
결론</h2>
기존 콜렉션에 대한 처리를 <code>par</code>함수를 통해 병렬 버전으로 바꾸어 넣는 것은 명백한 실수라고 생각한다. 병렬 처리 연산은 순차적 콜렉션에 들어 맞지 않는 연산 집합을 가지고 있고 모든 콜렉션이 <code>par</code>를 지원하지도 않으며 이 기능에 신경을 쓰지 않는 다른 사람들에게 부담을 안겨줄 위험을 가지고 있다.<br />
그리고 이 병령 컬렉션의 추가로 인해 스칼라는 내가 생각하기에 중요한 프로그래밍 언어와 API의 일반적인 률을 위반했다고 생각한다. 그 률은 '쓰이지 않을 것에 비용을 지불하지 말라' 라는 규칙인데 병렬 콜렉션이 단지 Jar파일에 몇MB 추가 된 것으로 그치지 않고 언어의 복잡성과 앞으로 이 언어를 유지 보수할 사람들에게 큰 짐을 안겨주엇다고 생각한다. 앞으로 누군가 순차적 콜렉션을 수정하고자 하면 그 수정 사항이 병령 콜렉션에게 영향이 없는지 검증을 해야 할 것이고 그 반대도 그렇다.<br />
스칼라 2.9는 꽤 최근에 발표된 버전이고 실제 세계에서 어느 정도의 이점을 얻고 있는지 정량적으로 파악이 안되는 것은 당연하다. 그러나 내가 예언하건데 용감한 개발자가 병렬 콜렉션의 기능들을 자신의 코드 베이스를 수정하는 노력을 기울여 얻을 수 있는 이득은 매우 적을 것이다. 그리고 더 나아가 콜렉션 내부를 루프를 돌면서 스레드를 생성하는 것은 이미 빠르게 동작하는 아주 적은 수의 요소를 가진 콜렉션에 대해 컨택스트 스위칭, 메모리 낭비, 캐시 미스등 많은 부정적인 사이드 이펙트를 낳게 될 것이다. 여기서 분명히 밝히지만 나는 어떤 정량적인 테스트를 하지 않은 상태로 얘기하는 것이라 내가 완전히 틀릴 수도 있다.<br />
이런 문제점들 때문에 병렬 콜렉션의 추가에 대해 흥분하지 않는 이유이며 누군가 이것의 유용함에 대해 나의 무지를 깨우쳐줄 수 있으면 좋을것 같다.<br />
여기서 내가 추천하는 병렬 콜렉션의 사용방법은<br />
<ul>
<li>병렬 콜렉션 버전과 순차적 콜렉션 버전을 완전히 분리하여 다른 용도로 사용하는 것을 추천한다.</li>
<li>Excutor 프레임웍을 구현하는 스칼라 래핑을 제공하여 저 수준의 병렬화를 구현하였으면 한다. 스레드 풀 사이즈도 조절이 가능하고 스레드 풀 자체도 변경이 가능하며 라이프 사이클등 모든 것을 컨트를 할 수 있는 형태로 말이다. 만약 시도한다면 몇 백 라인 정도로 이를 구현할 수 있을 것이며 <code>par</code>를 통해 가능한 것 보다 훨씬 더 유용할 것이다.</li>
</ul>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-7437750066641401062014-08-13T15:32:00.000-07:002014-08-13T15:34:37.231-07:00무료 온라인 팩스 서비스 추천최근에 물건 반품 건으로 American Express Purchase Protection 서비스를 이용하면서 물건의 영수증등을 팩스로 보내야 하는 일이 발생을 했다. 집전화 번호도 없고 회사에서 팩스를 부탁하기도 난감한 상황이라 여기저기 온라인 팩스 서비스를 많이 찾아 봤는데 대부분 팩스 문서에 광고를 붙인다거나 믿을 수 없을 정도로 지저분한 웹 UI 모습에 신뢰가 가질 않아서 중요한 서류를 보낼 수 가 없었는데 어쩌다 찾게 된 HelloFax 란 서비스가 있어서 여기에 소개를 한다.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRKJPjkqt6KCEaFx2WwI3N_4n6oW49Lgg6gSM5NafgDMh7o18Yd5EnIFLV8wQmXLpTqB_h6x8tgl6O1KxhR2YrVuZM4FdkQMMoXJOPuTS2A6DKtgxHI8lakL6vDuI9Zpk-JiDFjb9zPIE/s1600/Screen+Shot+2014-08-13+at+3.14.47+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRKJPjkqt6KCEaFx2WwI3N_4n6oW49Lgg6gSM5NafgDMh7o18Yd5EnIFLV8wQmXLpTqB_h6x8tgl6O1KxhR2YrVuZM4FdkQMMoXJOPuTS2A6DKtgxHI8lakL6vDuI9Zpk-JiDFjb9zPIE/s1600/Screen+Shot+2014-08-13+at+3.14.47+PM.png" height="336" width="640" /></a></div>
<div style="clear: none; float: none; text-align: center;">
</div>
<br />
초기 화면인데 이메일 혹은 구글 아이디로 간편히 가입을 할 수 있다. 깔끔한 첫 화면 구성이 다른 무료 팩스 서비스들과는 다른 느낌을 주어서 회원 가입하고 시도해보게 되었다.<br />
<br />
팩스를 보내는 방법은 아래 처럼 간단하다. 팩스 보낼 파일을 업로드하고 전화 번호를 적은 후 "Send it now" 버튼 한방이면 끝. 특히 이 서비스가 맘에 들었던 점은 Drop box, Google Drive, Evernote, One Drive,Box.com 등의 클라우드 스토리지에 있는 파일들을 선택하여 보낼 수도 있다는 점이다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRJ5OlwvXOBR9_Ye_bEB48S0YRudKFfcQNDM7F_Y7dD6J0KPXwgw34BwsVg1ty9lhqqkXdk89prrXXIbTGDL9TpUp9IYzEkOJfBISKPlDXeY4c_WaxNBZ_FcG23r0YRTQCa-ie88KJXo8/s1600/Screen+Shot+2014-08-13+at+3.14.23+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRJ5OlwvXOBR9_Ye_bEB48S0YRudKFfcQNDM7F_Y7dD6J0KPXwgw34BwsVg1ty9lhqqkXdk89prrXXIbTGDL9TpUp9IYzEkOJfBISKPlDXeY4c_WaxNBZ_FcG23r0YRTQCa-ie88KJXo8/s1600/Screen+Shot+2014-08-13+at+3.14.23+PM.png" height="380" width="640" /></a></div>
<br />
<br />
<div style="clear: none; float: none; text-align: center;">
<br /></div>
<div style="clear: none; float: none; text-align: center;">
그리고 파일을 전송 후 파일이 언제 전송되었는지 이력 확인도 가능하다. 그리고 팩스가 완전히 전송이 되면 이메일을 통해 전송이 완료되었을 알려준다. 팩스 보내는 양이 많다면 유용한 기능이 아닐 수 없다.</div>
<div style="clear: none; float: none; text-align: center;">
<br /></div>
<div style="clear: none; float: none; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgARmG5VO14unDLXHLkQtVGx-3e9AE4RTdhugE5_IMIqIUQ-wTF_WUrbq6sT9fkeB8NQeAQU6cSM5lYi_ZmFNAcsolwXOEFS7G4uXbrMuhd-tL2al6yIuiP_wRG3xsUTfIofIEbFalzo7g/s1600/Screen+Shot+2014-08-13+at+3.12.44+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgARmG5VO14unDLXHLkQtVGx-3e9AE4RTdhugE5_IMIqIUQ-wTF_WUrbq6sT9fkeB8NQeAQU6cSM5lYi_ZmFNAcsolwXOEFS7G4uXbrMuhd-tL2al6yIuiP_wRG3xsUTfIofIEbFalzo7g/s1600/Screen+Shot+2014-08-13+at+3.12.44+PM.png" height="348" width="640" /></a></div>
<div style="clear: none; float: none; text-align: center;">
<br /></div>
<div style="clear: none; float: none; text-align: center;">
<br />
일단 무료 계정으로는 5장까지 무료로 보낼 수 있다. 그러나 이정도의 간편하고 깔끔한 서비스라면 작은 기업에서는 팩스기기를 들여 놓는 대신 편리하게 쓸 수 있을것 같다.<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghbSb1CQc5rO6vKGC5qcKwiC9KjYXuVUICRSxF5uDERMY9hkB9oar_ePPbYNAnbmZ0GidnCKM-NKxl3sMsxx0_9cti11Yl9keUKM1bNtQmTjeD-MkMCwXZQVd-_yOazRQX_9C3Y4BH2V8/s1600/Screen+Shot+2014-08-13+at+3.13.26+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghbSb1CQc5rO6vKGC5qcKwiC9KjYXuVUICRSxF5uDERMY9hkB9oar_ePPbYNAnbmZ0GidnCKM-NKxl3sMsxx0_9cti11Yl9keUKM1bNtQmTjeD-MkMCwXZQVd-_yOazRQX_9C3Y4BH2V8/s1600/Screen+Shot+2014-08-13+at+3.13.26+PM.png" height="554" width="640" /></a></div>
<div style="clear: none; float: none; text-align: center;">
<br /></div>
<br />
<div style="clear: none; float: none; text-align: center;">
</div>
<br />
<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-16014883161814305822014-07-08T17:47:00.000-07:002014-07-08T17:51:52.754-07:00AngularJS에서 다른 Scope간 데이터를 공유하는 방법
<p>AngularJS로 웹 어플리케이션을 개발하다보면 서로 다른 scope간 데이터를 공유해야만 하는 경우를 종종 마주치게 되는데 이번에는 크게 3가지 정도로 데이터를 공유하는 방법을 살펴보도록 한다.</p>
<h2>Parent scope와 child scope간 데이터 공유</h2>
<p>3Scope간 Parent-Child관계가 성립이 되는 경우 아래의 방법을 이용할 수 있다.<br/>
AngularJS에서 scope는 prototypically상속을 받게 되는데 즉 어떤 property가 childe scope에서 정의되지 않았을 경우 parent scope를 통해 접근이 가능하다. parent scope의 멤버 변수는 childe scope의 `$scope.$parent' property을 통해 접근할 수 있다.</p>
<h3>JavaScript</h3>
<pre><code>function Parent($scope) {
$scope.x = 5;
$scope.y = 5;
}
function Child($scope) {
$scope.modifyBothScopes = function() {
$scope.$parent.x++;
};
$scope.modifyOnlyChildScope = function() {
// 멤버 변수 "y"가 child scope에 생성된다. 따라서 이 경우
// $scope.$parent.y++ 문장은 parent scope의 y값만을 변경한다.
$scope.y++;
};
}
</code></pre>
<h3>HTML</h3>
<pre><code><div ng-controller="Parent">
parentX = {{x}}<br/>
parentY = {{y}}<br/>
<div ng-controller="Child">
childX = {{x}}<br/>
childY = {{y}}<br/>
<a ng-click="modifyBothScopes()">ModifyBothScopes</a><br/>
<a ng-click="modifyOnlyChildScope()">modifyOnlyChildScope</a><br/>
</div>
</div>
</code></pre>
<p>아래의 경로를 통해 직접 확인해볼 수 있다.<br/>
<a href="http://jsfiddle.net/ramandv/JHwxP/" title="link">http://jsfiddle.net/ramandv/JHwxP/</a></p>
<h2>Service를 이용한 데이터 공유</h2>
<p>서로 독립적인 두 controller사이에 데이터를 공유해야 할 필요가 있을 경우 AngularJS의 Service를 이용할 수 있다. 공유할 데이터 모델을 가진 Service를 생성하고 해당 Service를 데이터 공유가 필요한 Controller에 의존성주입으로 데이터 공유를 하는 방법이다.</p>
<p>아래의 예제에서 Service는 변수 x를 저장하기 위해 사용이 되었고 독립적인 controller들 간에 x값을 공유하여 사용할 수 있다.</p>
<h3>JavaScript</h3>
<pre><code>angular.module('myApp', [])
.service('myService', function() {
var x = 5;
return {
increase: function() {
x++;
},
getX: function() {
return x;
}
};
})
.controller("ControllerA", function($scope, myService) {
$scope.x = 1;
$scope.incrementDataInService = function() {
myService.increase();
};
$scope.getDataInService = function() {
$scope.x = myService.getX();
};
})
.controller("ControllerB", function($scope, myService) {
$scope.x = 1;
$scope.incrementDataInService = function() {
myService.increase();
};
$scope.getDataInService = function() {
$scope.x = myService.getX();
};
});
</code></pre>
<h3>HTML</h3>
<pre><code><div ng-app="myApp">
<div ng-controller="ControllerA">
ControllerA.X = {{x}}<br/>
<a ng-click="incrementDataInService()">incrementDataInService</a><br/>
<a ng-click="getDataInService()">getDataInService</a><br/>
</div>
<hr/>
<div ng-controller="ControllerB">
ControllerB.X = {{x}}<br/>
<a ng-click="incrementDataInService()">incrementDataInService</a><br/>
<a ng-click="getDataInService()">getDataInService</a><br/>
</div>
</div>
</code></pre>
<p>아래의 경로를 통해 직접 확인해볼 수 있다.<br/>
<a href="http://jsfiddle.net/ramandv/kR859/" title="link">http://jsfiddle.net/ramandv/kR859/</a></p>
<h2>Service를 통해 공유된 데이터 변경을 모니터하기</h2>
<p>어떤 경우 서비스에서 변경된 사항을 캐치해야 할 경우가 있다. 이 경우를 위해서 AngularJS에선 <strong>"$broadcast"</strong>를 준비 해 두었다. $broadcast를 통해 변경된 데이터를 리스너들에게 넘겨줄 수 있다.</p>
<p>아래의 예제에서 ControllerA와 ControllerB는 "XChanged"라는 이벤트를 모니터링하고 있고 "myService" Service는 x값이 변경되었을때 "XChanged"라는 이벤트를 실제 x값과 함께 broadcast하고 있음을 알 수 있다.</p>
<h3>JavaScript</h3>
<pre><code>angular.module('myApp', [])
.service('myService', function($rootScope) {
var x = 5;
return {
increase: function() {
x++;
$rootScope.$broadcast('XChanged', x);
}
};
})
.controller("ControllerA", function($scope, myService) {
$scope.x = 1;
$scope.incrementDataInService = function() {
myService.increase();
};
$scope.$on('XChanged', function(event, x) {
$scope.x = x;
};
})
.controller("ControllerB", function($scope, myService) {
$scope.x = 1;
$scope.incrementDataInService = function() {
myService.increase();
};
$scope.$on('XChanged', function(event, x) {
$scope.x = x;
};
});
</code></pre>
<h3>HTML</h3>
<pre><code><div ng-app="myApp">
<div ng-controller="ControllerA">
ControllerA.X = {{x}}<br/>
<a ng-click="incrementDataInService()">incrementDataInService</a><br/>
<a ng-click="getDataInService()">getDataInService</a><br/>
</div>
<hr/>
<div ng-controller="ControllerB">
ControllerB.X = {{x}}<br/>
<a ng-click="incrementDataInService()">incrementDataInService</a><br/>
<a ng-click="getDataInService()">getDataInService</a><br/>
</div>
</div>
</code></pre>
<p>역시 아래의 경로를 통해 확인할 수 있다.<br/>
<a href="http://jsfiddle.net/ramandv/25CVc/" title="link">http://jsfiddle.net/ramandv/25CVc/</a></p>Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-47054936624000819192014-07-07T19:16:00.000-07:002014-07-08T17:50:45.087-07:00std::bind 활용하기<h1 id="stdbind-사용하기">std::bind 사용하기</h1>
<p>C++11 세계로 들어오면서 전에 보도 듣도 못한 여러가지 기능들이 추가되어 매우 혼란스럽다. 배움의 길이라 생각하고 마주치는 것들 하나하나에 대해 포스팅을 할 계획이다. 우선 그 첫번째로 <code>std::bind</code>.</p>
<h2 id="간단한-예제">간단한 예제</h2>
<p>아래와 같이 두개의 정수형 파라메터를 전달 받아 둘을 더하여 결과를 리턴하는 함수가 있다.</p>
<pre class="prettyprint prettyprinted"><code><span class="com">#include</span><span class="pln"> </span><span class="str"><iostream></span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> add</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> a</span><span class="pun">+</span><span class="pln">b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> add</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>컴파일 후 실행 결과는 당연하게도 다음과 같다.</p>
<pre class="prettyprint prettyprinted"><code><span class="lit">3</span></code></pre>
<p>이제 우리는 항상 위에서 정의한 add함수를 이용해 1,2를 더한 결과를 출력하는 함수를 원한다고 가정해보자.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">int</span><span class="pln"> add12</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> add</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>위와 같은 함수를 생각해 볼 수 있을 것이다. 그리고 조금 있다 위와 비슷하게 add함수를 이용해 3,4를 더해야 하는 함수가 필요해졌다. 그러면 <code>add34()</code>와 같은 함수를 또 만들 수 있을 것이다. 그러나 이런식으로 매번 문제를 해결해 나가면 끝도 없이 새로 정의되는 함수가 늘어만 갈 것이다. 만약 이런 함수 정의를 매번 쓸 필요없이 필요한 경우에 위와 같은 함수를 만들어 주는 기능이 있다면 매우 편리할 것이다. <br>
이것이 바로 <code>std::bind</code> 함수가 제공하는 기능이다.</p>
<h2 id="stdbind-사용하기-1">std::bind 사용하기</h2>
<p><code>std::bind</code> 를 사용하기 위해서는 <code><functional></code> 표준 라이브러리 해더를 include해주어야 한다. <code>std::bind</code>를 이용해서 위의 문제를 어떻게 깔끔하게 처리할 수 있는지 아래의 예제를 보자.</p>
<pre class="prettyprint prettyprinted"><code><span class="com">#include</span><span class="pln"> </span><span class="str"><iostream></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><functional></span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> add</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">auto</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>위의 코드의 결과는?</p>
<pre class="prettyprint prettyprinted"><code><span class="lit">3</span></code></pre>
<p>새로운 함수를 정의해서 처리했던 일을 bind 함수로 한방에 끝냈다. 깔금하지 않은가?</p>
<p><code>bind</code> 함수가 여기서 한 일은 첫번째 인자로 함수명을 받고 나머지 인자들을 첫번째 인자로 받은 함수의 인자에 <strong>bind</strong>해서 필요한 시점에 호출할 수 있는 객체를 만들어 준것이다. 일단 여기서 어떤 객체가 생성되었는지는 고민할 필요는 없다. 천천히 알아가도록 하자.</p>
<h2 id="변수-혹은-참조-바인딩">변수 혹은 참조 바인딩</h2>
<p>위의 예제에서는 상수를 바인딩하는 예제를 썼는데 변수 또는 참조 변수도 바인딩 가능하다. 아래 예제를 보자.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">auto</span><span class="pln"> addxy </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">);</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> addxy</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>변수들의 경우 bind가 호출되는 시점의 변수값으로 bind가 일어 난다는 것에 주의를 할 필요가 있다. bind이후에 변경된 변수값은 결과에 반영되지 않는다.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">auto</span><span class="pln"> addxy </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">);</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> addxy</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> addxy</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>위 예제의 결과는 3, 7이 아니라 3, 3이다. </p>
<p>그러나 이것을 해결할 방법도 있다. 아래의 예제와 같이 바인딩할 때 <code>cref</code>라는 헬퍼 함수의 도움을 받아 참조를 넘기면 된다.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">auto</span><span class="pln"> addxy </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> cref</span><span class="pun">(</span><span class="pln">x</span><span class="pun">),</span><span class="pln"> cref</span><span class="pun">(</span><span class="pln">y</span><span class="pun">));</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> addxy</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> addxy</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>위의 결과는 아래와 같이 이전과는 다른 결과를 보인다.</p>
<pre class="prettyprint prettyprinted"><code><span class="lit">3</span><span class="pln">
</span><span class="lit">7</span></code></pre>
<h2 id="placeholders">Placeholders</h2>
<p>한국말로 해석하기가 참 애매한데. 대체자 정도로 해석을 하면 되려나? 영어뜻 그대로 어떤 위치를 임시로 잡고 있는 것을 뜻하며 나중에 교체될 대상이 된다.</p>
<p>만일 우리가 첫번째 인자에 1을 더해서 반환하는 add1이라는 함수가 필요하다고 가정해보자. 그런데 그 함수를 위에서 정의한 add함수를 이용해서 어떻게 구현할 수 있는지 알아보자.</p>
<pre class="prettyprint prettyprinted"><code><span class="com">#include</span><span class="pln"> </span><span class="str"><iostream></span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str"><functional></span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">:</span><span class="pln">placeholders</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> add</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">auto</span><span class="pln"> add1 </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> _1</span><span class="pun">);</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> add1</span><span class="pun">(</span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>위의 예제의 결과는 예상했다시피 101을 출력한다. <br>
특별한 인자 _1이 눈에 띄는데 이것이 placeholder역할을 하며 <strong>std::placeholders</strong>의 네임스페이스에 정의되어 있다. _1은 바인딩된 함수가 호출이 될 때 (위의 경우 add1 함수) 인자로 넘겨받은 인자로 대체된다. 위의 예제에서 _1은 100으로 대체가 되어 add 함수가 호출이 되고 따라서 그 결과로 101이 출력되게 되는 것이다. </p>
<p>_1은 첫번째 인자로 대체되며 _2는 두번째 인자로 대체되고 나머지는 _3, _4.. 이런 식으로 바인딩된 객체가 호출이 될 떄 전달 받은 인자를 원래 함수에 전달할 수 있다.</p>
<h2 id="stdbind가-실제로-반환하는-것은">std::bind가 실제로 반환하는 것은?</h2>
<p>C++ 표준이 정해 놓은 것은 실제로 어떤식으로 동작을 해야 한다는 것에 대한 가이드 라인이지 그것이 어떻게 구현이 되어야 하는지에 대해서는 정의해놓지 않았다. 따라서 그 표준을 구현하는 주체에 따라 달라질 수 있기 때문에 아래에서는 GCC의 구현을 살펴보도록 하자.</p>
<p>예를 들어 아래의 코드는</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">auto</span><span class="pln"> f </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span></code></pre>
<p>GCC 컴파일러는 bind의 결과로 아래 타입을 반환한다</p>
<pre class="prettyprint prettyprinted"><code><span class="pln">std</span><span class="pun">::</span><span class="typ">_Bind_helper</span><span class="pun"><</span><span class="kwd">int</span><span class="pln"> </span><span class="pun">(&)(</span><span class="kwd">int</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">),</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">>::</span><span class="pln">type</span></code></pre>
<p>C++11에 auto가 없었다면 이것을 일일이 다 손으로 쳐야 할뻔했다. 뭐 이런 타입을 반환하는데 첫번째 파라메터로 받는 함수의 선언 형태나 전달되는 인자의 타입에 따라 리턴되는 타입도 달라진다.</p>
<p>만일 입력에 따라 어떤 경우에는 1,2 를 더해야 하고 어떤 경우는 3,4를 더한 결과를 출력해야 한다면 어떻게 해야 할까? 아래와 같은 코드를 써야 할까?</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">auto</span><span class="pln"> f</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> z</span><span class="pun">;</span><span class="pln">
cin </span><span class="pun">>></span><span class="pln"> z</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">z </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
f </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
f </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">);</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>auto 키워드의 역할에 대해 잘 알고 있는 사람은 알겠지만 위의 코드는 컴파일이 안된다. auto로 f가 선언되는 시점에 컴파일러는 f가 어떤 타입인지 알아야 하기 떄문이다. 대신 아래와 같이 쓸 수 있다.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
std</span><span class="pun">::</span><span class="kwd">function</span><span class="pln"> </span><span class="pun"><</span><span class="kwd">int</span><span class="pun">(</span><span class="kwd">void</span><span class="pun">)></span><span class="pln"> f</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> z</span><span class="pun">;</span><span class="pln">
cin </span><span class="pun">>></span><span class="pln"> z</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">z </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
f </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
f </span><span class="pun">=</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">add</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">);</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> f</span><span class="pun">()</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>위와 같이 <strong>std::function</strong> 객체를 이용한 해결 방법이 있다. <strong>std::function</strong>에 대해서는 다음번에 다시 알아보도록 하겠다.</p>
<h2 id="대체-이걸-어디에-쓰지">대체 이걸 어디에 쓰지?</h2>
<p>여기까지 예제를 살펴보아도 당장 이것을 어디에 활용할 수 있을 것인지에 대해서는 모호하다. 일반적으로는 어떤 함수의 기능을 원하지만 잘못된 수의 파라메터나 파라메터의 타입이 맞지 않는 경우 혹은 파라메터의 위치가 잘 맞지 않는 경우 사용한다고 볼 수 있다. </p>
<p>예를 들어 다음의 예제를 보자.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">template</span><span class="pln"> </span><span class="pun"><</span><span class="kwd">typename</span><span class="pln"> FUNC</span><span class="pun">></span><span class="pln">
</span><span class="kwd">string</span><span class="pln"> apply</span><span class="pun">(</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">&</span><span class="pln"> s</span><span class="pun">,</span><span class="pln"> FUNC f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">string</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">size_t</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun"><</span><span class="pln"> s</span><span class="pun">.</span><span class="pln">size</span><span class="pun">();</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
result </span><span class="pun">+=</span><span class="pln"> f</span><span class="pun">(</span><span class="pln">s</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>이 함수는 문자열과 특정 함수를 파라메터로 전달 받아 함수를 문자열의 각 캐릭터를 파라메터로 하여 호출하고 결과로써 새로운 문자열을 만들어 리턴한다. </p>
<p>싱글 문자를 파라메터로 받는 함수에 대해서는 이것은 잘 동작한다. 예를 들어 파라메터로 전달되는 함수가 다음과 같이 다음 ASCII코드에서 다음 문자를 리턴하는 함수라면</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">char</span><span class="pln"> nextchar</span><span class="pun">(</span><span class="kwd">char</span><span class="pln"> c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> c </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>다음과 같이 코드를 쓸 수 있다.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">string</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="str">"foobar"</span><span class="pun">;</span><span class="pln">
cout </span><span class="pun"><<</span><span class="pln"> apply</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> nextchar</span><span class="pun">)</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span></code></pre>
<p>그러나 우리가 만일 한개 이상의 파라메터를 받는 함수를 가지고 있다고 하자, 예를 들어 이 함수는 우리가 바꾸고 싶은 문자들의 리스트를 전달 받고 첫번째 파라메터로 전달받은 문자가 해당 문자들의 리스트에 포함이 되어 있으면 그 다음 문자를 리턴하는 함수라고 하자.</p>
<pre class="prettyprint prettyprinted"><code><span class="kwd">char</span><span class="pln"> nextif</span><span class="pun">(</span><span class="kwd">char</span><span class="pln"> c</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">&</span><span class="pln"> chars</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">char</span><span class="pun">.</span><span class="pln">find</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">string</span><span class="pun">::</span><span class="pln">npos</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> c </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> c</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<p>이 함수는 <strong>apply</strong> 함수에 어떻게 전달할 수 있을까?</p>
<pre class="prettyprint prettyprinted"><code><span class="pln">apply</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> nextif</span><span class="pun">)</span></code></pre>
<p>혹은</p>
<pre class="prettyprint prettyprinted"><code><span class="pln">apply</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> nextif</span><span class="pun">,</span><span class="pln"> </span><span class="str">"aeiou"</span><span class="pun">)</span></code></pre>
<p>둘다 불가능하다. 해답은 아래와 같이 <strong>std::bind</strong>를 이용하는 것이다!</p>
<pre class="prettyprint prettyprinted"><code><span class="pln">cout </span><span class="pun"><<</span><span class="pln"> apply</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> bind</span><span class="pun">(</span><span class="pln">nextif</span><span class="pun">,</span><span class="pln"> _1</span><span class="pun">,</span><span class="pln"> </span><span class="str">"aeiou"</span><span class="pun">))</span><span class="pln"> </span><span class="pun"><<</span><span class="pln"> </span><span class="str">"\n"</span><span class="pun">;</span></code></pre>
<p>위의 경우 처럼 bind의 결과를 바로 템플릿 함수로 넘길 수 있다. </p>
<p>여기까지 살펴보았을 때 “뭐야. apply같은 함수 안만들면 되지!”라고 반응할 수 도 있다. 그러나 C++ 표준 라이브러리의 <algorithm> 섹션을 보면 여기서 언급한 apply함수 같은 것들이 도처에 널려있음을 알 수 있고 따라서 <strong>std:bind</strong>의 사용은 필수적이라는 것을 알 수 있다. 그리고 또 다양한 use case를 스스로 발견해보기를 바란다.</algorithm></p>Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-21188215866446130052014-07-06T01:01:00.002-07:002014-07-06T01:07:39.422-07:00 Node 전문가가 Node를 떠나며 남긴 글.<h1>
TJ Holowaychuck이 Node.js를 떠나며 지적한 Node.js의 문제들</h1>
원문은 <a href="https://medium.com/code-adventures/4ba9e7f3e52b" target="_blank">이곳</a>에서 읽을 수 있습니다.<br />
<br />
나는 항상 C를 사랑해왔지만 C로 무엇인가를 해본 사람은 그것이 가치를 하면서도 에러를 만들어 내기 쉽다는 것을 알고 있을 것이다. 빠르게 결과물을 만들어 낼 수 없다는 이유로 매일 사용하는 언어로는 부적합하다. 그 언어의 단순함에 대해서는 항상 내가 동경해왔던 바이지만 대량의 표준 구현들이 없이는 멀리 나아가기는 힘들다.<br />
분산 시스템에 관련된 일을 더 하면 할 수록 나는 Node의 방향성에 대해 더 많이 좌절하게 되었다. 왜냐하면 그 방향성이 사용성과 견고함 보다는 항상 퍼포먼스에 방점을 두고 있기 때문이다. 최근 몇 주동안 나는 대규모 분산 시스템을 Go언어로 다시 개발하였고 그것이 견고하며 퍼포먼스도 뛰어나고 유지보수도 쉬우며 동기 코드들은 일반적으로 더 간결하고 뛰어나서 더 나은 테스트 커버리지를 갖고 있다는 것을 발견하였다.<br />
나는 Go언어가 최후의 성배라는 것을 얘기하려는 것이 아니다. 그것은 완벽하지는 않지만 언어로써 지금 존재하는 것 중 나에게 최적의 솔루션 처럼 보인다는 이야기이다. 소위 말하는 다음 세대의 언어로 일컫는 Rust나 Julia가 자신의 자리를 찾아가고 성숙해짐에 따라 우리는 더 대단한 솔루션을 갖게 될 것임을 확신한다.<br />
개인적으로 Go의 반복 속도에 대해 큰 흥미를 갖고 있다. 그리고 그것이 2.0버전을 향해 감에도 이미 뛰어난 것들을 포기하고 새로운 것을 시도하는데에 두려워하지 않는 다는 점에서 더욱 큰 흥미를 가지게 한다.<br />
수정: 내가 이메일 리스트에서 뭔가를 잘 못 본거 같다. 그들은 곧 과거와 단절되는 변화에 대해 더이상 반가지 않을 것 같다. 이것이 진실이다 하더라도 나는 혁신적 변화가 언어의 발전에 도움이 된다면 그들이 마다하지 않을 것임을 믿기 때문에 Go 언어를 계속 사랑할것이다.<br />
<h2>
왜 Go 인가</h2>
Node가 당신의 요구 조건에 맞다면 Node는 여전히 훌륭한 툴이다. 그러나 만일 어떤 것이 당신의 신경을 거슬린다면 한번 주위에 다른 어떤 것이 있는지 돌아보기를 권한다. 프로덕션 환경에서 단지 몇시간 동안 Go를 써본것 만으로도 나는 Go에 낚여들고 말았다.<br />
다시 한번 말하지만 Go가 완벽한 언어라고 얘기하고 싶은 것은 아니다. 그러나 단지 그것의 역사에 비교하면 굉장히 성숙되어 있고 이미 견고한 언어이며 리팩토링은 단순하고 즐거우며 Go를 위한 툴들도 (프로파일링, 디버깅) 훌륭하다. 그리고 커뮤니티도 문서화와 포맷팅, 벤치마켕과 API 디자인에 관해 이미 정교한 규칙들을 가지고 있다.<br />
처음에 Go를 접했을 때 Node의 극도의 모듈화에 익숙해져 있었고, Ruby의 끔찍한 stdlib의 대부분을 경험해본 나는 Go의 stdlib는 끔찍한 것이라고 생각했었다. 그러나 Go언어를 조금 더 심도있게 접근해보고 난 뒤 Go stdlib의 압축, json, IO, buffered IO, 문자열 조작등 라이브러리의 대부분은 현재 프로그램들의 정수를 잘 집어 낸 것임을 깨닫게 되었다. 이 API들은 잘 정의되어 있으면 굉장히 강력하다. 한 프로그램의 전체를 단지 stdlib으로만 만들 수 있을 정도다.<br />
<h2>
서드파티 Go 패키지</h2>
대부분의 Go 라이브러리는 굉장히 비슷하게 구성되어 있고 내가 지금껏 겪어보고 일해본 대부분의 서드 파티 코드는 굉장히 질적으로 우수하다. 이것은 유저들의 실력이 천차만별인 Javascript 코더들이 대부분이 Node의 세계와는 대비되는 일이다.<br />
Go 패키지들을 위한 중앙 저장소는 존재하지 않는다. 따라서 5개나 6개의 패키지들이 같은 이름을 갖고 있는것을 종종 발견하게 된다. 처음에는 이것이 매우 혼란스러울 수 있으나 흥미로운 부작용을 낳고 있다. 어떤 것이 괜찮은 것인지 알기 위해 하나씩 리뷰를 해보아야만 하는 것이다. Node의 세계에서는 표준 처럼 보이는 이름을 가진 패키지들이 있다. 가령 "redis", "mongodb-native", "zeromq" 같은 것들은 딱 보기에 표준 처럼 보이기 때문에 같은 기능을 하는 다른 패키지들을 찾기보다는 이것들이 최적의 솔루션이다라고 착각하고 이것들에 머물게 되며 더 나은 것들을 찾을 노력을 하지 않게 된다.<br />
<h2>
Go VS Node</h2>
만일 당신이 분산 처리 작업을 하고 있다면 Go의 동시성에 관련된 기본 요소들이 매우 설명적이라서 굉장히 편리함을 느낄 수 있을 것이다. 우리는 이와 비슷한 것들을 Node에서 제네레이터를 통해 성취할 수도 있지만 내 의견으로는 아직 갈길이 멀다고 생각한다. 스택 에러 핸들링과 리포팅을 분리하지 않고는 기껏해야 반쯤의 성공이 될 것이다. 그리고 우리가 지금 현재 잘 동작하는 솔루션을 가지고 있는데에도 불구하고 3년간 커뮤니티가 단편화되지 않도록 기다리고 싶지도 않다.<br />
Go의 에러 처리는 매우 뛰어나다고 생각한다. Node는 모든 에러 상황에 대해 생각을 해야 하고 어떻게 처리할지 결정해야 한다는 점에서 뛰어나지만 아래의 이유로 실패라고 생각한다.<br />
<ul>
<li>중복된 콜백을 받을 수 있다.</li>
<li>콜백을 전혀 받지 못할 수도 있다.</li>
<li>out-of-band 에러를 받을 수도 있다.</li>
<li>emitter가 다수의 에러 이벤트를 뿜어낼 수도 있다.</li>
<li>에러 이벤트를 잃게 되는 경우 모든 것을 망가지게 만든다.</li>
<li>에러 핸들러가 무엇을 해야할지 확실치 않은 경우가 많다.</li>
<li>에러 핸들러는 매우 장황하다.</li>
<li>콜백 자체가 별로다.</li>
</ul>
Go에서는 내 코드가 끝났으면 정말 끝이 난 것이다. 코드 라인이 다시 실행되는 경우는 절대 없다. Node에서는 이것이 사실이 아니다. 당신이 루틴이 완전히 종료되었다고 생각했는데도 라이브러리가 몇번씩 콜백을 다시 부르는 경우도 있고 핸들러가 완전히 정리되지 않아서 코드가 다시 실행되는 경우도 있다. 이 경우들은 라이브 환경에서 문제를 찾아내기 굉장히 힘든 경우들에 속한다. 왜 이런것들에 의해 고통을 받는가? 다른 언어들은 이런 고통을 겪게 하지 않는데 말이다.<br />
<h2>
노드의 미래</h2>
난 여전히 노드가 잘 되길 기원한다. 수 많은 사람들이 많은 시간을 투자를 했고 그것이 잠재력도 있다고 생각한다. Joyent와 팀은 Node의 사용성에 더 많은 투자를 하기를 원한다. 왜냐하면 해당 언어로 개발된 어플리케이션이 취약하고 디버깅이 힘들고 리팩토링 개발이 힘들다면 퍼포먼스는 의미가 없다고 생각하기 때문이다.<br />
4~5년 동안 여전히 “Error: getaddrinfo EADDRINFO” 같은 알아보기도 힘든 에러가 지속되고 있는 점은 어디에 우선순위가 있었는지를 반증한다. 물론 시스템의 코어에만 집중하고 있었다면 이러한 것 쯤은 간과할 수 있음을 이해는 하지만 유저들은 이런한 것들에 대해 수차례 이야기를 해왔지만 어떤 결과로도 이어지지 않았다.<br />
스트림은 잘 동작하지 않고 콜백은 별로 좋은 방법이 아니며, 에러는 모호하다. 툴 들도 여전히 별로며 커뮤니티 규칙도 있기는 있는것 같은데 Go 커뮤니티의 그것에 비하면 부족하다. 그럼에대 불구하고 웹사이트를 개발하는 것 같은 분야에는 노드를 계속 사용할 것 같다. Node가 기본적인 문제들을 해결한다면 여전히 관련되어 있을 것 같지만 그러나 사용성에 앞서 퍼포먼스를 강조하는 것으로는 일이 해결될것 같지 않다. 특히나 다른 솔루션은 퍼포먼스와 사용성 두가지 토끼를 모두 잡고 있는 마당에 말이다.<br />
노드 커뮤니티가 제네레이터를 포용하고 Node의 코어로 적극 구현하여 에러 전달을 아주 잘 할 수 있다면 에러 처리에 관한 분야에서는 비교가 될 수 있을 것이다. 그리고 이것은 극적으로 Node의 사용성과 견고함을 향상 시킬것이다.<br />
한가지 좋은 소식은 오랫 동안 Node의 코어에 기여한 StrongLoop의 멋진 사람들과 얘기를 했었는데, 그들은 정말로 개발자들의 플랫폼에 대한 피드백에 대한 이야기를 듣고 올바른 방향성을 가지고 현재의 이슈들을 해결할 방향과 계획을 세워서 미래에는 더 즐겁게 사용할 수 있는 Node버전을 만들겠다고 한다. 그러나 Node 코어에 관련한 일을 하고 있는 몇개의 회사들 사이의 논쟁이 어떻게 끝날지는 모르겠지만 개발자들이 이끄는 방향이 결국엔 승리할 것이라고 생각한다.<br />
지금까지 말한 것들은 Node와 함께 일하는 정말로 능력있는 그 누구를 비방하려고 하는 것은 아니지만 이제 Node에 대한 관심은 없다. 커뮤니티의 일원으로써 많은 멋진 사람들을 만났고 좋은 시간들을 보냈다.<br />
결국 내가 하고 싶었던 이야기는 절대 당신이 파놓은 우물속에만 갇혀있지 말고 주위에 뭐가 있는지 둘러보라는 이야기이다. 멋진 솔루션들이 도처에 존재하니깐 말이다.Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-15222405917120525102014-07-03T16:07:00.001-07:002014-08-10T00:15:48.313-07:00매버릭스에 WireShark 설치하기한참 헤매대가 해결방법을 발견하고 포스팅. 최신 맥버전의 WireShark를 설치하면 X11을 찾는데 매버릭스로 업데이트 이후에 X11이 시스템에 기본으로 들어 있지 않아서 (아마 마운틴라이언부터 일지도.) X11을 별개로 설치를 해야만 한다.<br />
<br />
스텝 바이 스텝으로 매버릭스에서 WireShark 쓰기 설명을 하자면.
<br />
<br />
먼저 X11 environment를 설치한다.<br />
<a href="http://xquartz.macosforge.org/landing/">http://xquartz.macosforge.org/landing/</a> 이곳에서 다운 받을 수 있다.<br />
<br />
두번째 <a href="http://www.wireshark.org/download.html" target="_blank">WireShark</a>를 설치한다.<br />
<br />
WireShark를 설치후 Application에서 WireShark를 실행하면 X11을 찾을 수 없다고 불평을 해대는데, "Browse" 버튼을 누르고 /Application/Utilities/XQuartz.app을 찾아서 선택해준다.<br />
<br />
그러고 나도 아무일도 일어나지 않고 창이 뜨지않을 것이다. 그러나 WireShark는 여전히 실행중인 상태. Dock에서 WireShark를 우클릭하여 앱을 죽인다. (Cmd+Q로도 가능).<br />
<br />
그리고 이번에는 XQuartz.app을 찾아서 실행한다. 그리고 터미널 윈도우에서 아래를 타이핑한다.<br />
<br />
<blockquote class="tr_bq">
<pre style="background-color: #eeeeee; border: 1px solid rgb(221, 221, 221); color: #535353; font-size: 12px; line-height: 16.600000381469727px; padding: 0.75em 1.5em;">/Applications/Wireshark.app/Contents/MacOS/Wireshark</pre>
</blockquote>
<br />
이 명령어를 실행하면 WireShark를 X11 환경에서 실행하게 된다. 여기서 시간이 꽤 걸리므로 커피한잔하고 오면 WireShark가 짠 하고 실행되어 있을 것이다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0kO5hzRLkVp2h9PlcIg8C7A4RAjZ_NC7AzxytaCSuqCHL_9aCvueEjiQI7InWBXHapxgeaUOBApxVxoF_ESfdl9DjZG9vyDcvjvd6Cr8jS5EnRyiWep-aiRz2u3foO-aCJI0B8VrdE3U/s1600/Screen+Shot+2014-07-03+at+4.06.27+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0kO5hzRLkVp2h9PlcIg8C7A4RAjZ_NC7AzxytaCSuqCHL_9aCvueEjiQI7InWBXHapxgeaUOBApxVxoF_ESfdl9DjZG9vyDcvjvd6Cr8jS5EnRyiWep-aiRz2u3foO-aCJI0B8VrdE3U/s1600/Screen+Shot+2014-07-03+at+4.06.27+PM.jpg" height="390" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
<br />
이제 다음 부터는 이런 절차를 거치지 않고도 Dock에서 Wireshark를 실행하면 빠르게 바로 실행이 될것이다.<br />
<br />
<br />
<br />
<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-88852814056637418452014-07-01T11:17:00.001-07:002014-08-10T00:15:57.608-07:00[WebDevelopment] 부트스트랩(Bootstrap) 테마 마켓오늘 우연히 AngularJS 관련 튜토리얼을 살펴보다가 부트스트랩 템플릿 및 테마 마켓을 발견했다. <a href="https://wrapbootstrap.com/" target="_blank">{wrap}bootstrap</a> 이란 사이트인데 최근 유행하는 웹서비스 레이아웃 디자인은 거의 대부분이 있는 듯 해 보이고, UX/UI디자인과 감각이 좀 있으면 직접 부트스트랩 테마를 만들어서 마켓에서 직접 팔 수도 있다.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEEn8F5VoH2rl1OLRIoh0o3P0SXamOPKkuE9np3sp47wzLk7rjXJ4MpMlNELurYJVknrEiIgXKdtP10WhE0bUuUvR-fyif0iqx0zX8dnbWhgDP3IRdn-Dz2Y37m-h4RyiR_Ch_fxJqNsc/s1600/Screen+Shot+2014-07-01+at+10.57.06+AM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEEn8F5VoH2rl1OLRIoh0o3P0SXamOPKkuE9np3sp47wzLk7rjXJ4MpMlNELurYJVknrEiIgXKdtP10WhE0bUuUvR-fyif0iqx0zX8dnbWhgDP3IRdn-Dz2Y37m-h4RyiR_Ch_fxJqNsc/s1600/Screen+Shot+2014-07-01+at+10.57.06+AM.jpg" height="443" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
해당 사이트에서 가장 잘 팔리는 Ace라는 Admin 템플릿의 경우 현재 $18에 팔고 있는데 11726카피나 팔렸으니 해당 템플릿 개발자는 $200,000이상 매출을 올린것인데 wrapbootstrap의 수익 배분율을 찾아 보니 해당 사이트에서 exclusive하게 즉 wrapbootstrap에서만 템플릿을 판매하는 경우 매출의 35%를 wrapbootstrap이 가지고 여러 다른 사이트에서도 판매하는 경우 판매 금액에 따라 55%~75%를 수수료로 떼고 수익을 배분한다고 한다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQhHPwezVYt04Zp_T39emStPTTvGXEVmOGy3nJ40E0H99a47aheraAbyR6jWDBTbzqDSBHaNRaIdr1qCw9kGj-52qi86R5kURTDOkQwUZDEZi1reIcsC4HV5Tjz_1qv8pcLsEVw6MG5d4/s1600/Screen+Shot+2014-07-01+at+11.08.31+AM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQhHPwezVYt04Zp_T39emStPTTvGXEVmOGy3nJ40E0H99a47aheraAbyR6jWDBTbzqDSBHaNRaIdr1qCw9kGj-52qi86R5kURTDOkQwUZDEZi1reIcsC4HV5Tjz_1qv8pcLsEVw6MG5d4/s1600/Screen+Shot+2014-07-01+at+11.08.31+AM.jpg" height="380" width="640" /></a></div>
<br />
<br />
<br />
<a href="http://wrapbootstrap.com/preview/WB0914026">http://wrapbootstrap.com/preview/WB0914026</a> 테마를 이용해서 만든 사이트 예제를 보면 <a href="http://rboaventura.com/f1feeder/#/drivers">http://rboaventura.com/f1feeder/#/drivers</a> 꽤 그럴듯 하다. 웹 frontend 코딩만 좀 할 줄 알고 아이디어만 있으면 디자이너 없이도 쓸만한 사이트 하나는 뚝딱 만들어 볼 수 있을듯.<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-25488554225484454882014-04-04T19:15:00.000-07:002014-04-04T19:18:04.352-07:00[iOS] 인증서와 코드 사이닝 이해하기iOS개발을 하면서 가장 헷갈리는 컨셉중 하나는 개발중인 앱을 실제 디바이스에서 실행되도록 하는 과정이다. 이 과정은 개인키, 공개키, 인증서, 프로비저닝 프로파일등 뭐가 뭔지 모르겟는 컨셉들이 마구 등장하기 때문인데 앱을 사이닝하면서 배포하는 과정에서 어떤 일어 나는지 알아 보면서 어려운 개념들을 하나하나 이해해보기로 하자.<br />
먼저 왜 앱개발자들이 이런 것들을 이해를 해야 하냐고 따진다면,<br />
<blockquote>
단지 애플만이 자신들의 하드웨어에서 어떤 소프트웨어가 동작하도록 허락된 주체이기 때문이다.</blockquote>
이것은 절대명제이며 많은 사람들이 이런 컨셉을 싫어해서 아이폰을 탈옥시켜서 애플로부터 해방되려고 애쓰는 이유이기도 하다.<br />
실제로 매번 앱이 실행될때마다 앱은 애플로 부터 인증을 받았는지 그래서 앱을 실행할 수 있는 권한이 주어졌는지 확인을 한다.<br />
<h2>
Apple 인증서</h2>
애플만이 앱을 실행할 권한을 가진다면 개발자들은 어떻게 디바이스에서 테스트를 할 수 있나? 해답은 애플이 개발자를 신뢰하여 애플 대신 앱을 실행할 수 있는 권한을 부여받는다.<br />
iOS Developer program의 개발자 센터에서 인증서를 받는 것으로 시작한다. 여기서 인증서란 매우 특별한 인증서로 개발자가 애플 대신 앱을 사인할 수 있는 권한을 인증받음을 의미한다. 이 인증서를 받기 위해서는 키체인 접근 앱에서 Certificate Signing Request(CSR)를 생성해야한다. 이때 "Request a Certificate from a Certificate Authority" 과정에서 두가지 일들이 일어나는데,<br />
<ol>
<li>먼저 키체인 앱은 공개키와 개인키를 자동으로 생성한다. 이 키는 Keychain앱의 "Key" 카테고리에서 확인할 수 있다. 이 키는 당신이 정말로 누구인지 애플에 알리는 정말로 중요한 키이므로 앱을 배포후 키를 잃어버려 더이상 앱스토어에 배포할 수 없는 상황을 맞이할지도 모르므로 적절한 곳에 잘 보관하여야한다.</li>
<li>다음이자 마지막으로 이 키를 이용하여 애플에 보낼 CertSingingRequest 파일을 생성한다. 이 파일은 당신의 이름, 이메일, 공개키를 포함하고 있고 개인키를 이용하여 사인된다. 이 공개키, 개인키 매커니즘으로 애플은 정말 당신이 이것을 만들었다는것을 알 수 있게 된다.</li>
</ol>
이 CSR을 애플에 업로드하면서 인증서를 요청하면 애플측에서는 간단한 확인 작업을 거친후 개발 인증서를 발급해준다. 개발자는 이 인증서를 받아서 키체인앱에 드래그드롭으로 추가하면 "My Certificate" 카테고리에 추가됨을 확인할 수 있고 더블클릭하여 자세한 내용을 보면 이 인증서는 애플을 통해 발급되었고 애플은 당신이 누구인지를 신뢰한다는 정보를 담고 있다. 이 인증서는 잠시후 앱을 사인할 때 사용된다.<br />
<h2>
Provisioning Profile</h2>
당신이 누구인지를 애플에 알림으로써 애플이 당신에게 인증서를 발급함으로써 앱을 사인할 수 있도록 허락은 받은 상태라고 볼 수 있는데 한가지 더 필요한것은 당신의 아이폰/아이패드가 당신을 신뢰할 수 있는지를 알아야 앱 설치를 허락할지 말지를 결정할 수 있다. 여기서 프로비저닝 프로파일 파일이 필요성이 발생한다.<br />
프로비저닝 프로파일을 만든다는 것은 당신의 iOS디바이스들을 앞 단계에서 만든 인증서와 연결하는 것을 의미한다. 그 결과로 만들어진 *.mobileprovision 파일은 당신의 iOS앱을 컴파일하는 과정에서 사용 되며 또한 앱을 테스트하려고 하는 디바이스에 설치가 되어야 한다. 프로비저닝 프로파일을 설치하는 방법은 Provisioning Portal에서 다운 받은 파일을 더블클릭하면 XCode가 인식하고 자동으로 프로비저닝 프로파일 목록에 저장한다.<br />
개발자는 복수의 프로비저닝 프로파일을 가질 수 있다. 그러나 프로비저닝 프로파일을 생성할때 연동한 App Id와 실제 컴파일하려는 앱에 설정된 ID가 일치하여야 하므로 결국은 각 프로젝트마다 각각의 프로비저닝 프로파일을 만들게 될 것이다.<br />
<h2>
앱을 빌드하고 실행하는 과정에서 일어나는 일</h2>
이제 당신이 누구인지를 증명하는 공개키와 비밀키를 가지고 있고 애플에서 당신이 누구인지를 확인받고 앱을 서명할 수 있음을 허락받은 인증서를 가지고 있다. 또한 서명된 앱을 당신의 디바이스에서 사용할 수 있도록 해주는 프로비저닝 프로파일을 가지고 있다. 이제 앱을 빌드하여 실제 디바이스에 배포할 수 있는 모든것을 갖추었다고 볼 수 있다.<br />
빌드하기 위해서 XCode를 어떻게 설정해야 하는지는 다른 글에서 정보를 얻기를 바라며 여기서는 빌드된 앱이 어떤 식으로 앞에서 설명한 서명, 인증서, 프로비저닝 프로파일이 사용되는지를 알아보자.<br />
Xcode에서 빌드를 하면 <em>.app 파일을 얻게 되는데 사실 이것은 하나의 파일이 아니고 앱의 모든 것을 답고있는 하나의 폴더라는 것을 알 수 있다. Finder에서 </em>.app 파일을 오른쪽 클릭 후 "Show Package Contents"를 클릭하면 그안에 있는 내용을 볼 수 있다. 다른 모든 포르젝트 파일들 중 주목할 만한 것은<br />
<ol>
<li>실제 프로비저닝 프로파일 : 이것은 컴파일할때 사용한 것과 같은 프로비저닝 프로파일 파일의 복사본이다.</li>
<li>"_CodeSignature" 폴더: "CodeResources"란 파일을 담고 있는데 이것은 단순한 plist파일이지만 패키지에 있는 모든 파일의 암호화된 해쉬정보를 담고 있다.</li>
</ol>
앱이 최종적으로 디바이스에 인스톨 될 때 iOS에서는 많은 일들이 일어난다. 먼저 앱에 포함된 프로비저닝 프로파일이 애플에서 서명된 것인지를 확인하고 다음으로 "CodeResources"란 파일에 기록된 각 파일의 해쉬 정보를 실제의 파일들과 확인을 하여 어떤 파일도 빌드 후에 수정이 되지 않았음을 확인한다. 이중 어떤 과정에 문제가 있으면 앱은 설치되지 않는다.
그리고 마지막으로 앱을 실행할때도 확인과정을 거친다. iOS는 앱이 변조되지 않았음을 확인하고 디바이스에 앱에 포함된 프로비저닝 프로파일과 같은 프로비저닝 프로파일을 가지고 있는지 확인한다.<br />
<h2>
다른 배포 과정</h2>
Ad-hoc 배포는 위에서 설명된 과정과 거의 같은 과정을 거치고 같은 과정으로 앱은 설치되고 실행된다.<br />
Enterprise 배포는 약간 다른데, 당신의 회사가 수많은 iPhone유저들을 가진다고 하면 애플은 그런 회사를 더 신뢰할 수 있는 충분한 이유가 있으므로 개발자에게 개발자가 정말로 애플인것처럼 개발한 앱들을 서명할 수 있는 인증서를 발급해준다. 따라서 이 인증서로 서명된 앱들은 따로 확인을 거치지 않고, 모든 디바이스를 애플에 등록하지 않고도 개발된 앱을 디바이스에서 바로 실행할 수 있도록 해준다. 그 외는 비슷한 과정을 거친다.<br />
마지막으로 설명할 것은 앱스토어 배포과정인데, Enterprise배포와 비슷하지만 이 배포과정에 포함되는 프로비저징 프로파일은 빌드된 앱이 어떤 디바이스에서도 실행이 되지 않도록 한다. 앱스토어를 위해 빌드된 앱은 앱스토어 제출 용도 말고는 어디에서도 쓸 수가 없다. 그리고 애플측에 앱을 제출되었을때는 이 앱은 당신에 의해 이미 서명되었고 프로비저닝 파일을 가지고 있기 때문에 애플에 인증된 개발자가 제출한 앱임을 확인할 수 있다. 그리고 애플측에서 이 앱을 승인하면 애플에서 자신들의 서명을 다시 함으로써 이 세상의 모든 iOS 디바이스에서 실행될 수 있도록 해주는 것이다.<br />
나도 iOS 앱을 개발하면서 이것들이 대체 죄다 뭐하는 거며 어디에 쓰길래 이렇게 사람을 귀찮게 하나 궁금했는데 과정을 하나하나 풀어보니 아 이래서 이런것들이 필요하구나 하는 감이 이제야 잡힌다.Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com4tag:blogger.com,1999:blog-4567551370435954890.post-79042431836034386932014-02-23T01:39:00.001-08:002014-02-23T01:46:27.277-08:00[Node.js] Node.js의 이벤트 루프 이해하기아래 글은 이곳(<a href="http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop">http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop</a>/)의 글을 번역한 글임을 밝힙니다. 그리고 이 글의 내용은 node.js의 기본적인 내용을 어느 정도 숙지하고 있다는 전제하에 쓰여진 글입니다.<br />
<br />
<br />
node.js에서 가장 기본이 되는 전제는 I/O에 드는 비용이 비싸다는 것이다. (아래의 표는 각 I/O를 처리하는데에 CPU에서 얼마만큼의 cycle이 소요되는지를 나타낸 표이다.)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://blog.mixu.net/files/2011/01/io-cost.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://blog.mixu.net/files/2011/01/io-cost.png" /></a></div>
<br />
현재의 프로그래밍 기술에서 가장 큰 손실은 I/O가 끝나기를 기다리는 데서 온다. 이렇게 퍼포먼스에 영향을 미치는 것을 처리 하기 위한 몇가지 방법이 있다.<br />
<br />
<ul>
<li>동기적 해결 : 하나의 요청을 한번에 처리하기. 장점: 단순하다. 단점: 어떤 요청이 끝나기를 다른 요청은 기다려야만 한다.</li>
<li>새로운 프로세스를 만들기 : 각 요청을 처리하기 위해 매번 새로운 프로세스를 만들어 해결한다. 장점: 쉽다 단점: 확장성이 떨어진다. 만약 수백개의 연결이 만들어 진다면 수백개의 프로세스가 만들어 지는 것을 의미한다. 이것은 문제를 해결하지만 과도한 방법이다.</li>
<li>스레드: 각 요청을 처리하기위해 스레드를 만든다. 장점:쉽다, 프로세스를 만드는 것보다는 OS커널에 친절하고 비용이 적게 드는 방법이다. 단점: 스레드 프로그래밍은 아주 복잡해지기 쉽다. 특히 공유되는 자원에 접근하게 되는 경우에 특히 그렇다.</li>
</ul>
<div>
각 연결당 하나의 스레드를 만드는 것은 메모리를 과도하게 소비하게 된다. </div>
<div>
아파치는 멀티스레드 프로그램이다. 각 요청당 스레드를 하나씩 생성한다. (설정에 따라 프로세스를 fork하기도 한다.) 동시 접속이 늘어 남에 따라 생성되는 스레드가 얼마나 많은 메모리를 소비하는지 볼 수 있다. 이러한 단점을 극복하기 위해 Nginx와 Node.js는 멀티 스레드 프로그램으로 설계되지 않았다. 이것들은 싱글 스레드 프로그램이지만 이벤트에 기반한 프로그램이다. 싱글스레드 설계로 수천개의 스레드 혹은 프로세스가 생성될때 생기는 과부하를 제거하였다. </div>
<div>
<br /></div>
<div>
<h4>
Node.js는 당신의 코드를 싱글 스레드로 유지한다.</h4>
</div>
<div>
<br /></div>
<div>
Node.js는 정말로 싱글스레드로 동작한다. 동시에 실행되는 코드를 만들 수 없다. 1초 동안의 "sleep" 코드는 정말로 서버를 1초동안 중단시킨다.</div>
<div>
<br />
<pre class="brush:js">while(new Date().getTime() < now + 1000) {
// do nothing
}
</pre>
<br />
<br /></div>
<div>
<div class="p3">
node.js에서는 당신의 코드를 실행하는 스레드가 정말로 하나이기 때문에 따라서 위의 코드가 동작하는 동안은 다른 어떠한 요청에도 node.js는 응답하지 않는다. 혹은 CPU자원을 많이 쓰는 코드(예를 들어 이미 리사이징같은..)를 동작하는 동안에도 해당 코드가 실행이 끝날때까지 다른 요청을 처리하지 못하게 된다.</div>
<div class="p3">
<br /></div>
<div class="p3">
<h4>
그러나 당신의 코드만 빼고 다른 모든 것은 병렬적으로 실행된다.</h4>
</div>
<div class="p3">
<br /></div>
<div class="p3">
하나의 요청을 처리하는 코드내에서 어떤 코드도 다른 요청에 대한 처리와 함께 병렬적으로 실행되도록 하는 방법은 없다. 그러나 모든 I/O 작업은 이벤트지향적이며 비동기적으로 동작한다. 따라서 다음의 코드는 서버의 동작을 멈추지 않는다.</div>
<div class="p3">
<br />
<br />
<pre class="brush:js">c.query(
'SELECT SLEEP(20);',
function (err, results, fields) {
if (err) {
throw err;
}
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<html><head><title>Hello</title></head><body><h1>
Return from async DB query</h1>
</body></html>');
c.end();
}
);
</pre>
<br />
<br /></div>
<div class="p4">
<span class="s3">당신이 위의 코드를 어떤 하나의 요청처리 중에 포함시킨다면 해당 코드의 데이터베이스 작업 (즉 20초간 sleep하기)이 끝날때까지 다른 요청 들이 정상적으로 처리가 된다.</span></div>
<div class="p4">
<span class="s3"><br /></span></div>
<div class="p4">
왜 이것이 좋은가? 그리고 언제 우리의 코드는 비동기적/병렬 처리를 하게 되는가?</div>
<div class="p4">
<br /></div>
<div class="p4">
동기적 처리도 코드의 단순성에서 보았을 때 나쁘지 않다. (스레드를 사용하는 코드에 비교할때, 가끔은 스레드의 동시성은 우리를 미치게 만든다.)</div>
<div class="p4">
<br /></div>
<div class="p4">
Node.js를 사용할때 당신은 뒷단에서 무슨 일이 일어나는지 걱정할 필요없이 단지 I/O작업이 필요할때 I/O작업이 끝난 후 처리될 callback만 넘겨 주면 된다. 그러면 당신의 I/O작업이 포함된 코드는 새로운 스레드나 프로세스의 생성할 필요 없이 다른 요청이 처리되는 것을 막지도 않으면서 처리됨을 보장받을 수 있다. </div>
<div class="p4">
<br /></div>
<div class="p4">
I/O작업은 보통 대부분의 다른 어떤 코드보다 비용이 비싼 작업으로 I/O작업이 끝나기를 기다리기 보다는 무엇인가 의미있는 일을 수행해야만 한다. 따라서 이런 경우 비동기적 I/O처리는 매우 유용하다.</div>
<div class="p4">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://blog.mixu.net/files/2011/01/bucket_3.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://blog.mixu.net/files/2011/01/bucket_3.gif" /></a></div>
<div class="p4">
<br /></div>
<div class="p4">
이벤트 루프란 코드 외부의 이벤트들을 처리하고 그것의 결과를 callback으로 전달하는 객체로 정의할 수 있다. 어떤 한 요청 처리 도중 I/O콜이 일어나서 기다려야 하는 순간 node.js는 다른 요청을 처리하게 된다. 이 I/O콜이 일어날 때 코드에서는 callback을 등록하고 컨트롤을 node.js 의 runtime environment로 넘기게 된다. 그리고 callback은 I/O콜이 완료된 순간 그 결과를 전달 받아 호출되게 된다.</div>
<div class="p4">
<br /></div>
<div class="p4">
따라서 당연히도 <a href="http://stackoverflow.com/questions/3629784/how-is-node-js-inherently-faster-when-it-still-relies-on-threads-internally" target="_blank">뒷단에서는 스레드들과 프로세스들이 DB 접속과 프로세스 실행을 위해 준비되어 있다</a>. 그러한 스레드와 프로세스는 당신의 코드와는 관계 없이 실행되고 있고 당신의 코드를 만들면서 신경쓸 필요가 없다. 단지 한 요청내에서의 I/O작업들은 비동기적으로 수행된다는 것만 생각하면 된다. node.js의 뒷단에서 여러 스레드와 프로세스들이 I/O처리를 완료후 이벤트 루프를 통해 당신의 코드로 결과를 전달 받게 된다. 정말 병렬 작업이 필요한 경우에만 스레드 혹은 프로세스가 생성이 되고 그것 조차도 node.js가 관리를 하게 되므로 아파치 서버 모델과 비교할 떄 훨씬 적은 수의 스레드와 프로세스만이 동작하게 된다.</div>
<div class="p4">
<br /></div>
<div class="p3">
I/O콜을 제외하고 node.js는 모든 요청이 굉장히 빨리 처리 될 것을 가정하고 만들어졌다. 따라서 <span id="goog_2075673312"></span>CPU를 많이 사용하게 되어서 느리게 처리되는 작업<span id="goog_2075673313"></span>이 있다면 <a href="http://www.slideshare.net/pgriess/nodejs-concurrency" target="_blank">WebWorkers</a>를 이용하거나 이벤트를 통해 실행과 결과를 주고 받을 수 있는 <a href="http://stackoverflow.com/questions/3491811/node-js-and-cpu-intensive-requests" target="_blank">다른 프로세스로 분리</a>가 되어야 한다. 이는 당신의 코드는 이벤트롤 통해 상호작용할 수 있는 스레드가 백그라운드에서 돌지 않으면 절대로 병렬화 될 수 없음을 의미한다. 기본적으로 모든 이벤트를 방출하는 오브젝트는 비동기적 이벤트 상호작용을 지원하며 당신은 블록된 코드와 이러한 방식으로 상호작용 할 수 있다. 예를 들어 파일을 사용하거나 소켓, 자식 프로세스 이런 것들은 모두 node.js에서 EventEmitters이다. <a href="http://developer.yahoo.com/blogs/ydn/multi-core-http-server-nodejs-8037.html" target="_blank">멀티코어의 사용</a>도 이러한 방식으로 접근할 수 있다. node-http-proxy도 한번 보길 바란다.</div>
<div class="p3">
<br /></div>
<div class="p3">
<h4>
내부 구현</h4>
</div>
<div class="p3">
<br /></div>
<div class="p3">
내부적으로는 node.js는 <a href="http://software.schmorp.de/pkg/libev.html" target="_blank">libev</a>를 통해 이벤트 루프를 구현한다. 그리고 <a href="http://software.schmorp.de/pkg/libeio.html" target="_blank">libeio</a>를 통해 스레드 풀을 통해 비동기적 I/O를 달성할 수 있도록 보조하고 있다. 더 알고 싶으면 <a href="http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod" target="_blank">libev documentation</a>을 참고하기를 바란다.</div>
<div class="p3">
<br /></div>
<div class="p3">
그래서 Node.js에서 어떻게 async를 구현하지?</div>
<div class="p3">
<br /></div>
<div class="p3">
Tim Caswell의 <a href="http://creationix.com/jsconf.pdf" target="_blank">멋진 프리젠테이션</a>을 통해 패턴을 알아 보자.</div>
<div class="p3">
</div>
<ul>
<li>First-class functions : function이 데이터 처럼 전달될 수 있으며 필요한 경우 실행될 수 도 있다.</li>
<li>Function composition : I/O작업중 어떤 이벤트가 발생했을 때 실행될 수 있는 이름이 없는 함수들과 클로져를 사용한다.</li>
<li>Callback counters : I/O 이벤트가 어떤 순서로 발생할 지 알 수 없다. 따라서 만일 여러개의 쿼리가 완료되어야 한다면 일반적으로 동시에 실행되는 I/O 작업의 숫자를 세고 필요한 모든 I/O작업이 완료되었는지 기다린다. 즉 예를 들어 <a href="http://stackoverflow.com/questions/4631774/coordinating-parallel-execution-in-node-js" target="_blank">DB쿼리가 몇개나 리턴이 되었는지를 이벤트 콜백에서 세어서</a> 모든 데이터를 가지게 된 순간 더 진행하도록 한다. I/O라리브러리가 지원하기만 한다면 여러개의 쿼리는 동시에 실행되게 된다. (Connection pooling등을 이용하여.)</li>
<li>이벤트 루프 : 앞에서 언급했듯이 blocking 코드를 예를 들어 자식 프로세스를 실행하여 처리후 결과를 받는 등의 이벤트 추상화로 감쌀 수 있다. </li>
</ul>
<div>
정말로 쉽죠?</div>
<div>
<br /></div>
</div>
<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-48081638653388586762014-02-09T02:09:00.000-08:002014-02-09T02:09:20.026-08:00[Android] 하나의 TextView에 서로 다른 여러 스타일의 텍스트를 입력하기TextView를 하나만 써서 여러 가지 스타일을 가진 텍스트를 입력해야만 할 때가 있다. 아래 방법을 알기 전에는 스타일이 바뀔때마다 TextView를 생성해서 배치를 해야 하나 생각했다. 그런데 안드로이드에서 지원되는 생각외로 간단한 방법이 있어서 소개한다.
<br />
<br />
<script src="https://gist.github.com/cromit/8896987.js"></script>
위와 같이 TextView의 텍스트에 Html이 지원된다. 모든 태그가 지원 되는 것은 아니고 지정한 몇가지만 가능한데 이 <a href="http://commonsware.com/blog/Android/2010/05/26/html-tags-supported-by-textview.html" target="_blank">링크</a>를 참고하여 지원되는 태그를 확인해보도록 하자.Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-53081605265272739682014-02-02T23:12:00.000-08:002014-02-02T23:12:45.137-08:00[Android] dp to px or px to dp안드로이드 앱 개발을 하다가 보면 DP 단위를 Pixel 단위로 바꾸거나 그 반대로 해야할 일이 종종 생긴다.<br />
<br />
아래 코드에 두가지 변환을 할 수 있는 함수가 있다. 이렇게 기본적으로 많이 쓰이는 유틸리티 함수들은 따로 클래스를 만들어서 모아 두면 편리할 것 같다.<br />
<br />
<br />
<script src="https://gist.github.com/cromit/8779869.js"></script>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-1795383763140725762014-02-02T23:03:00.002-08:002014-02-02T23:04:10.568-08:00[Android] Drawable String형 이름으로 Integer형 리소스 아이디 찾기간단한 팁이지만 필요할 때가 종종 있다.<br />
<br />
여기선 두가지 방법을 소개하는데 하나는 Java의 Reflection을 이용한 방법이고 (아래 소스 코드 위쪽 방법) 하나는 Android API에서 제공되는 Method를 이용한 방법이다. (아래 소스 코드의 아래쪽 방법)<br />
<br />
Reflection을 이용한 방법이 성능상의 이점이 있다고 한다. 그러나 현재 작업 중인 프로젝트의 패키지가 아닌 다른 패키지에서의 리소스 아이디를 알아야 할 일이 있다면 Android API를 이용한 방법이 유용할 것 이다.<br />
<br />
<br />
<br />
<script src="https://gist.github.com/cromit/8779753.js"></script>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-80019469939037636062013-12-03T14:20:00.003-08:002014-08-10T00:16:16.752-07:00fluid - 모바일 UI 디자인 프로토타이핑<a href="https://fluidui.com/" target="_blank">fluid</a>라는 모바일 UI 디자인 프로토타이핑툴을 소개하려고 한다. 웹상에서 모바일 앱의 UI를 각 위젯을 Drag & Drop하는 방식으로 목업 제작이 가능하다. 또한 레이아웃 디자인뿐 아니라 각 버튼을 다른 페이지에 연결하여 클릭 액션까지 확인이 가능하다.<br />
<div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlisU6TkM25OHnHFMVPMhiJqdSamQTSdOspGmiBEXOF1SFzx8xvB1kDg29TiJP4RrqlIeWVYDHwV_SF7dWWJOo4_Fhvd5x0E4TPen-RVUNVM5hP8N7tCHGoJx6y_rMaKpDx6HzfMZCu6U/s1600/Screen+Shot+2013-12-03+at+1.38.40+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlisU6TkM25OHnHFMVPMhiJqdSamQTSdOspGmiBEXOF1SFzx8xvB1kDg29TiJP4RrqlIeWVYDHwV_SF7dWWJOo4_Fhvd5x0E4TPen-RVUNVM5hP8N7tCHGoJx6y_rMaKpDx6HzfMZCu6U/s640/Screen+Shot+2013-12-03+at+1.38.40+PM.jpg" height="452" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Android, iOS, Windows Phone 등의 다양한 위젯 스타일을 지원하며, 커스텀 아이콘을 업로드도 가능하다.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-wyE4n2bKQ4g/Up5ZBvTanUI/AAAAAAAAGfA/mdRnJLh6r78/s1600/Screen+Shot+2013-12-03+at+2.19.33+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-wyE4n2bKQ4g/Up5ZBvTanUI/AAAAAAAAGfA/mdRnJLh6r78/s640/Screen+Shot+2013-12-03+at+2.19.33+PM.jpg" height="640" width="376" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
무료 버전은 한개의 앱에 최대 10페이지까지만 만들어 볼 수 있다는 것이 사용함에 있어 단점이라면 단점.</div>
<div>
<br /></div>
<div>
백문이 불여일행. 직접 한번 써보고 판단하도록 하자. </div>
<div>
<br /></div>
<div>
<a href="https://fluidui.com/">https://fluidui.com/</a><br />
<div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh59qgbhGHtfxwLU88p0MNSg5XnEoNYm_1oyLwtNBU9IhUv_bxEJBc4vm27KB6Yz8zcp0bHkXSYefXdJeBWmbvHDY08e9dLtQ2BJB-P_MaHq5SuRpH8COvdAOuQbbX295TgCjXQr9B4GOI/s1600/Screen+Shot+2013-12-03+at+1.38.27+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh59qgbhGHtfxwLU88p0MNSg5XnEoNYm_1oyLwtNBU9IhUv_bxEJBc4vm27KB6Yz8zcp0bHkXSYefXdJeBWmbvHDY08e9dLtQ2BJB-P_MaHq5SuRpH8COvdAOuQbbX295TgCjXQr9B4GOI/s640/Screen+Shot+2013-12-03+at+1.38.27+PM.jpg" height="382" width="640" /></a></div>
<br />
<div>
<br /></div>
</div>
</div>
</div>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com1tag:blogger.com,1999:blog-4567551370435954890.post-78054700927765696372013-12-01T22:00:00.005-08:002013-12-01T22:00:49.400-08:00Amazon Prime Air - Drone을 활용한 아마존의 실험.인터넷 쇼핑몰의 최강자 아마존에서 또 한번 혁신을 위한 한걸음을 내딛었다. <a href="http://www.amazon.com/b?ref_=tsm_1_tw_s_amzn_mx3eqp&node=8037720011" target="_blank">Amazon Prime Air</a>라는 프로젝트를 발표했는데 간략히 요약하자면 드론(무인 비행물체)를 활용한 실시간 배송서비스이다. 아마존 프라임이라는 서비스는 아마존에서 1년에 $79 정도를 내면 프리미엄 서비스를 받을 수 있는데, 2일 무료 배송, 아마존에서 제공하는 티비쇼, 영화등을 스트리밍으로 무제한으로 볼 수 있는 서비스, 무료로 디지털 책을 빌려 볼 수 있는 서비스 등이 포함되어 있다.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8Z_KGhh4W9Ni7ViG5-PvUOzLgjm4MwIhnWDpWg2arwMr2OOuhERKLnXEqo9R_Kose56CPOuZ0yeoYuYFC4XOWZrlW4cf8JD1hKZf3kzDxv7RCAS2JsxLrQVRCf8HAr7MIOfZDu92RaIs/s1600/Screen+Shot+2013-12-01+at+9.08.35+PM.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="334" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8Z_KGhh4W9Ni7ViG5-PvUOzLgjm4MwIhnWDpWg2arwMr2OOuhERKLnXEqo9R_Kose56CPOuZ0yeoYuYFC4XOWZrlW4cf8JD1hKZf3kzDxv7RCAS2JsxLrQVRCf8HAr7MIOfZDu92RaIs/s640/Screen+Shot+2013-12-01+at+9.08.35+PM.jpg" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">위의 스샷을 통해 볼 수 있듯이 드론이 패키지를 운반하여 고객의 집으로 실어 나르고 있다.</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
원데이 쉬핑도 모자라 이제 "실시간" 배송이라니!! 이미 미국에서 인터넷 쇼핑업계는 아마존이 평정하다시피했는데 좀 쉬어가도 되련만 얘네는 스타트업도 아닌것이 지속적인 혁신을 일구어 내고 있다. 처음에 이 프로젝트 소개 페이지를 접했을때는 오늘이 만우절인가? 라는 생각을 했다. 너무나도 황당한 시나리오 였기 때문이다. </div>
<div>
<br /></div>
<div>
고객이 아마존에서 물건을 주문하자 마자 아마존 웨어하우스에서 고객이 선택한 상품이 재고에서 빠져나와서 레일을 따라 드론이 이륙 준비중인 곳으로 자동으로 운반된다. 상품이 드론에 도킹되어 드론이 이륙하고 정확히 고객의 집을 찾아 물건을 사뿐히 내려 놓은뒤 다시 웨어하우스로 되돌아간다.</div>
<div>
<br /></div>
<div>
공상과학소설에서 가능할 것만 같은 일이 실제로 준비되고 있다. 이러한 혁신적인 프로젝트가 아마존같이 큰 기업에서 준비되고 있다는 것이 더욱 놀랍다.</div>
<div>
<br /></div>
<div>
프로모션 동영상을 한번 보도록 하자.<br />
<br /></div>
<iframe allowfullscreen="" frameborder="0" height="315" src="//www.youtube.com/embed/98BIu9dpwHU?rel=0" width="100%"></iframe>
Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-72656356280408246272013-11-21T13:59:00.000-08:002013-11-21T13:59:17.145-08:00[Android] Genymotion최신 버전에서 삭제된 구글 플레이 스토어와 ARM Translation기능 추가하기최근에 소개한 Android Emulator의 대안 Genymotion이 최근에 큰 업데이트를 하면서 라이센스 문제로 인해 제공하는 Android Rom에서 구글 앱과 ARM Translation기능을 <a href="https://plus.google.com/u/0/+GenymotionEmulator/posts/jNF8Kwu5p1c" target="_blank">제거</a>하였다. 나로썬 Unity에서 개발한 게임을 주로 Genymotion VirtualMachine에서 테스트하곤 하였는데 Unity는 x86 타겟의 앱빌드를 지원하지 않는다. 따라서 Genymotion 업데이트와 함께 Unity 게임이 동작하지 않음으로 인해 활용 가능성이 확 떨어졌는데 역시 XDA의 용자님들께서 해결 책을 내놓으셨다.<br />
<br />
XDA Developers의 원문 링크는 <a href="http://forum.xda-developers.com/showthread.php?t=2528952" target="_blank">여기</a>로.<br />
<br />
<br />
절차는 굉장히 간단하다.<br />
<br />
1. 이 <a href="http://goo.gl/JBQmPa" target="_blank">링크</a>(<a href="http://goo.gl/JBQmPa" rel="nofollow" style="background-color: white; color: #d38339; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; text-decoration: none;" target="_blank">http://goo.gl/JBQmPa</a>)에서 ARM Translation Installer를 다운 받는다.<br />
2. 다운 받은 zip파일을 드래그하여 Genymotion VirtualMachine 에 드롭한다. File Transfer 창이 뜨고 잠시후 아래 스샷과 같은 창이 나타난다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje36fbtdMvfI-qifmefmakm8pmpXFUmLo9cSQThbt8LDAIZIb3kj5oNUwGAXdjyTcGFOzmJj3GthWGA1h0t8Tq5JU2ElCdMGngKpFTYJz-6SeGa2nAkJc9iNrB4ePsLHYApPES1HD0B-o/s1600/Screen+Shot+2013-11-21+at+1.40.48+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="395" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje36fbtdMvfI-qifmefmakm8pmpXFUmLo9cSQThbt8LDAIZIb3kj5oNUwGAXdjyTcGFOzmJj3GthWGA1h0t8Tq5JU2ElCdMGngKpFTYJz-6SeGa2nAkJc9iNrB4ePsLHYApPES1HD0B-o/s640/Screen+Shot+2013-11-21+at+1.40.48+PM.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
OK 를 선택</div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcwcsz6ma8j19ZhzQ10AIWrA3HtI8fJyFOqlAnoK7rStBtavWB5e5ey4Lg_ISKeOa8Ysz8CdGLEANLgQ8ZQtJbLQVaR1Vj1vVsr7u63GOWzfxGdNktHwCLI4XKt0koyC5xle6FbAtv20k/s1600/Screen+Shot+2013-11-21+at+1.40.59+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcwcsz6ma8j19ZhzQ10AIWrA3HtI8fJyFOqlAnoK7rStBtavWB5e5ey4Lg_ISKeOa8Ysz8CdGLEANLgQ8ZQtJbLQVaR1Vj1vVsr7u63GOWzfxGdNktHwCLI4XKt0koyC5xle6FbAtv20k/s640/Screen+Shot+2013-11-21+at+1.40.59+PM.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
성공적으로 인스톨이 되었고 버추얼 디바이스를 리붓을 해야 한다. 오른쪽 아래 파워 버튼을 이용해서 디바이스를 셧다운 하고 다시 시작한다. 이제 ARM Translation Library는 추가되어서 Unity에서 빌드한 앱을 설치하고 실행할 수 있다.</div>
<br />
3. 이번엔 구글 플레이 스토어를 사용하기 위해 구글 앱들을 설치하자.<br />
<span style="color: red;">주의 : 버추얼 디바이스의 안드로이드 버전에 따라 다른 구글 앱 패키지를 설치해야 한다.</span><br />
<ol style="background-color: white; color: #222225; font-family: Arial, Helvetica, sans-serif; font-size: 13.333333969116211px; padding-left: 20px;">
<ul style="list-style-type: disc; padding-left: 20px;">
<li style="margin-left: 2em;">Google Apps for Android 4.3 - <a href="http://goo.im/gapps/gapps-jb-20130813-signed.zip" rel="nofollow" style="color: #d38339; text-decoration: none;" target="_blank">http://goo.im/gapps/gapps-jb-20130813-signed.zip</a></li>
<li style="margin-left: 2em;">Google Apps for Android 4.2 - <a href="http://goo.im/gapps/gapps-jb-20130812-signed.zip" rel="nofollow" style="color: #d38339; text-decoration: none;" target="_blank">http://goo.im/gapps/gapps-jb-20130812-signed.zip</a></li>
<li style="margin-left: 2em;">Google Apps for Android 4.1 - <a href="http://goo.im/gapps/gapps-jb-20121011-signed.zip" rel="nofollow" style="color: #d38339; text-decoration: none;" target="_blank">http://goo.im/gapps/gapps-jb-20121011-signed.zip</a></li>
</ul>
</ol>
4. 버전에 맞는 구글 앱 패키지를 다운받아 zip 형태의 파일을 버추얼 디바이스에 드래그&드롭하도록 하자. 마찬가지로 File Transfer 창이 나타나고 ARM Translation Library를 설치할 떄와 마찬가지 방법으로 워닝창에서 OK를 선택후 버추얼 디바이스를 재시작하도록 하자.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinrgbW8ANPEB2jH3ol7TIipO-hfbYFcYo9Zp0bm7PNxZjCbJ4tHO8c90EqhAJDUn4dtd94jttrl46f-IEuiUkxgyDg7H0FUPL0J7skQFX84KJMmaUfxnwbO9GZKJ_fhyphenhyphenNoYH9dcy21ufw/s1600/Screen+Shot+2013-11-21+at+1.56.12+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinrgbW8ANPEB2jH3ol7TIipO-hfbYFcYo9Zp0bm7PNxZjCbJ4tHO8c90EqhAJDUn4dtd94jttrl46f-IEuiUkxgyDg7H0FUPL0J7skQFX84KJMmaUfxnwbO9GZKJ_fhyphenhyphenNoYH9dcy21ufw/s640/Screen+Shot+2013-11-21+at+1.56.12+PM.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
App Drawer에서 Play Store, Gmail등 구글 핵심 서비스가 등록된것을 볼 수 있다.</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRTRv3ioNBj8sf97JWJEhdc6lXL6KDcGJGaY0nGiCQ-CDWrRXBZdXUi6qj7q9muU3nwri61oJq0X7ixLKAi3gts-QHTdXAqftEjk5Jn4rrM4zsyXBWSIQ4akn-SphbqgKzey3Zj0CghUA/s1600/Screen+Shot+2013-11-21+at+1.56.48+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="394" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRTRv3ioNBj8sf97JWJEhdc6lXL6KDcGJGaY0nGiCQ-CDWrRXBZdXUi6qj7q9muU3nwri61oJq0X7ixLKAi3gts-QHTdXAqftEjk5Jn4rrM4zsyXBWSIQ4akn-SphbqgKzey3Zj0CghUA/s640/Screen+Shot+2013-11-21+at+1.56.48+PM.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
Goolgle 계정으로 로그인 하면 구글 플레이 스토어를 사용할 수 있다.</div>
<br />
이상으로 Genymotion에서 ARM 기반 바이너리와 구글 플레이 스토어를 사용할 수 있는 방법을 알아 보았다.<br />
<br />
<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-65681698880476976942013-11-20T23:37:00.003-08:002013-11-20T23:38:06.561-08:00공개 종료된 MMORPG 게임의 모든 리소스를 무료로 공개하다<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW2daejsIsCGP-tyHcewW-QZ1xdJLaRd02K6vMlkq3jPz66OXoJIxcnPoSHpDlconU3EUMLZDdyrDeHEH6OHL0YcW_3Js8-Pa9LfGPKt1QiajpxxGr5ef-tTZk_x2KQpQ8KlWlIyLtYQI/s1600/Screen+Shot+2013-11-20+at+11.24.59+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="534" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW2daejsIsCGP-tyHcewW-QZ1xdJLaRd02K6vMlkq3jPz66OXoJIxcnPoSHpDlconU3EUMLZDdyrDeHEH6OHL0YcW_3Js8-Pa9LfGPKt1QiajpxxGr5ef-tTZk_x2KQpQ8KlWlIyLtYQI/s640/Screen+Shot+2013-11-20+at+11.24.59+PM.jpg" width="640" /></a></div>
<br />
공개 종료된 게임의 모든 리소스를 무료로 공개하였다. Glitch라는 MMORPG인데 흔히 한국 사람이 생각하는 리니지같은 형태의 MMORPG는 아니고 아래 동영상에서 볼 수 있듯이 웹브라우저상에서 실행되는 독특한 횡스크롤타입의 온라인 게임이다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/ecoYEgVAWmE?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
더이상 이 게임의 서비스는 하지 않지만 이 게임에 사용된 모든 리소스와 서버 소스코드까지 제작사에서 공개하였다. 게임은 서비스 중단되어 사라지지만 게임에 사용된 리소스는 누군가의 손에서 다시 새로운 모습으로 탄생을 꿈꾸게 될지도 모른다. 제작자들도 아마도 그런 마음으로 공개한 것이리라.. 서양의 이러한 공유와 개방에 바탕을 둔 개발문화는 참 바람직한것 같다.<br />
<br />
<a href="http://www.glitchthegame.com/public-domain-game-art/" target="_blank">http://www.glitchthegame.com/public-domain-game-art/</a><br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-58609915917838697692013-11-11T15:13:00.004-08:002013-11-11T15:13:37.282-08:00[Android] 안드로이드 시뮬레이터의 대안 Genymotion안드로이드 어플리케이션 개발과정에서 가장 마음에 안드는 점을 고르라면 아마도 안드로이드 시뮬레이터를 대부분의 개발자들이 뽑을 것이다. iOS 시뮬레이터와 윈도우즈 폰 에뮬레이터에 비교하면 안드로이드 에뮬레이터는 과연 이것을 쓰라고 만든것인지. 구글의 개발자 지원이 이것밖에 안된다는 것에 상당한 실망을 하게된다. <br />
<br />
특히 느려터진 퍼포먼스 때문에 아마도 대부분의 개발자들이 에뮬레이터에서 테스트는 포기하고 실제 디바이스를 가져다가 개발하며 디바이스에서 테스트 해 가며 열악한 상황에서 개발을 하고 있으리라 사료된다.<br />
<br />
이러한 상황에서 안드로이드 개발자들을 구원하고자 <a href="http://www.genymotion.com/about/" target="_blank">Genymotion</a>이 등장했다.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgE_lRBqxwfK0r7H7STLPNgZOzT_culKxTyE1LGK7f1mk6p9bdO9v2UdPIwSNwz4ng7q71MyMCCokA3XnVdMlbIX56M3G-4FYwWwakmOFcX1o5NmBFT0B5I0fOBBN2H6SCOoG85dMNCvs/s1600/Genymotion+is+a+product+of+Genymobile+group+++Genymotion.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="380" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgE_lRBqxwfK0r7H7STLPNgZOzT_culKxTyE1LGK7f1mk6p9bdO9v2UdPIwSNwz4ng7q71MyMCCokA3XnVdMlbIX56M3G-4FYwWwakmOFcX1o5NmBFT0B5I0fOBBN2H6SCOoG85dMNCvs/s640/Genymotion+is+a+product+of+Genymobile+group+++Genymotion.png" width="640" /></a></div>
<br />
Genymotion은 VirtualBox 위에서 돌아가는 안드로이드 버츄얼 머신으로써 강력한 개발 머신위에서라면 심지어 실제 안드로이드 디바이스보다도 좋은 성능으로 안드로이드 OS를 돌릴 수 도 있다. 이러한 이점을 얻기 위해 내가 들여야 하는 노력은 심지어 안드로이드 개발 SDK를 설치하는 것보다 간단하다.<br />
<br />
OSX 상에서는 VirtualBox를 설치하고 Genymotion을 설치하면 끝.<br />
빠르다는 이점외에도 Genymotion 개발사에서 직접 관리하고 있는 Android Rom 을 통해 신뢰할 수 있는 안드로이드 버츄얼 머신으로 내가 만든 앱을 테스트할 수 있다. 그리고 또 하나의 장점은 버츄얼 머신에 빌트인된 하드웨어에 대한 컨트롤을 제공하는 점이다. 아래 스샷을 통해 볼 수 있듯이 GPS를 에뮬레이터하면서 동시에 쉽게 현재 위치를 조작할 수 있는 UI를 제공한다. 카메라, 배터리 등도 마찬가지로 여러가지 옵션을 쉽게 조정할 수 있다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1wj9HqjMgLsK9ZrZ2Hbmsgolx4SckymQVZxgPy3y3HRztjvVBBg-wrwZ15pHIaM3CgZqxq-j4fshoSMN19zkCRYS3s4BE2I6tkUGUhZg-2bQZL74sKfWzpCfNB9U_LNsN-hvcbyV4InE/s1600/Screen+Shot+2013-11-11+at+2.06.46+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="414" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1wj9HqjMgLsK9ZrZ2Hbmsgolx4SckymQVZxgPy3y3HRztjvVBBg-wrwZ15pHIaM3CgZqxq-j4fshoSMN19zkCRYS3s4BE2I6tkUGUhZg-2bQZL74sKfWzpCfNB9U_LNsN-hvcbyV4InE/s640/Screen+Shot+2013-11-11+at+2.06.46+PM.jpg" width="640" /></a></div>
<br />
<br />
그리고 또 하나는 Genymotion에서 제공하는 롬중에 안드로이드 앱들이 설치된 채로 배포되는 롬이 있다. 이 롬을 사용하면 구글 플레이 스토어에 접속하여 다른 앱들을 다운로드 받아 에뮬레이터에 설치할 수 도 있다. 거의 실제 디바이스와 다를바 없이 동작하게 되는 것이다.<br />
<br />
그리고 Android Studio/Eclipse 플러그인을 제공함으로써 개발 툴과 fully integrated 된 개발이 가능하다는 점이다.<br />
<br />
이런 장점들에 반해 약간의 버그가 조금씩 있는데 이제 베타란 딱지를 붙이고 출시된 프로덕이라 앞으로 많이 개선이 되리라 예상된다. 물론 Genymotion에 테스트 되었다고 실제 하드웨어 디바이스에서 테스트 하지 않아도 되는 것은 아니지만 개발에 속력을 붙여 줄 것은 확실하다.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-4074690850627273192013-10-30T13:15:00.002-07:002013-10-30T13:15:25.613-07:00프로 자바스크립트 프로그래머가 되기 위해 알아야할 6가지 필수 요소RaphaelJS의 개발자 Dmitry Baranovskiy라는 사람이 얘기하는 프로 Java Script 프로그래머가 되기 위해 알아야할 6가지 필수요소에 대해 알아보자. 나는 사실 자바 스크립트 프로그램을 만들지 않는다. 그러나 언젠가는 나에게 닥칠 일로 예상되어 꼭 알아 두어야 하는 과제 같은것으로 마음속 귀퉁이에 짐으로 남아 있다. 일단 이 사람이 이야기하는 내용은 프로 자바스크립트 프로그래머가 되기 위해서는 기초 체력을 탄탄히 다져야 한다는 것이고 그것이 이 사람의 식스팩 이론이다. (열심히 근육을 단련시켜 복근을 만드는 그 식스팩이다.)<br />
<br />
그가 아래 슬라이드에 나오는 자바스크립트 코드의 실행 결과를 정확하게 예측할 수 있는가? 정확한 정답을 알고 있다면 당신은 아마도 자바스크립트의 식스팩을 갖추고 있다고 말할 수 있을 것이다.<br />
<br />
<br />
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="356" marginheight="0" marginwidth="0" scrolling="no" src="http://www.slideshare.net/slideshow/embed_code/13295219" style="border-width: 1px 1px 0; border: 1px solid #CCC; margin-bottom: 5px;" width="100%"> </iframe> <br />
<div style="margin-bottom: 5px;">
<strong> <a href="https://www.slideshare.net/Dmitry.Baranovskiy/javascript-enter-the-dragon" target="_blank" title="JavaScript: enter the dragon">JavaScript: enter the dragon</a> </strong> from <strong><a href="http://www.slideshare.net/Dmitry.Baranovskiy" target="_blank">Dmitry Baranovskiy</a></strong> <br />
<br />
<br />
<br /></div>
</div>
프리젠테이션에 나와있는 코드의 실행 결과는 다음과 같다.<br />
<br />
<h3>
1. Types & type coercion </h3>
<br />
<pre class="brush:js">> 5 - "4"
1
> 5 + "4"
54
> +!{}[true]
1
> +[1]
1
> +[1, 2]
Nan
> 7 - "a"
Nan
> 7 / 0
Infinity
</pre>
<br />
<h3>
2. Operators </h3>
<br />
<pre class="brush:js">> 5 + "4"
"54"
> 5 + null
5
> 4 == "4.00"
true
> null == undefined
true
> 0 == false
true
> 0 == null
false
> null == false
false
> typeof null == "object"
true
> typeof function () {} == "function"
true
</pre>
<br />
<br />
<h3>
3. Object * primitives </h3>
<br />
<pre class="brush:js">> var a = "string"
undefined
> a.length
6
> a.t = 3
undefined
> a.t
undefined
</pre>
<br />
<br />
<h3>
4. Function * constructors </h3>
<br />
<pre class="brush:js">> function f() {};
undefined
> var a = f, b = f(), c = new f, d = f(f);
undefined
> a
function f() {}
> b
undefined
> c
f {}
> d
undefined
</pre>
<br />
<br />
<h3>
5. Closures </h3>
<br />
<pre class="brush:js">> function add(a) { return function (b) { return a + b; }; }
undefined
> add(3)(4) == 7
true
</pre>
<br />
<br />
<h3>
6. Prototype </h3>
<br />
<pre class="brush:js">> function f() {};
undefined
> f.prototype.x = 3;
3
> var a = new f;
undefined
> a.x = 2;
2
> a.y = 1;
1
> var b = new f;
undefined
> f.prototype = { z: 0 };
Object {z: 0}
> var c = new f;
undefined
> b.constructor == f
true
> c.constructor == Object
true
</pre>
<br />
나 역시 자바스크립트를 배우고 있는 입장이라 직접 실행해보기 전에는 이 모든 코드의 결과를 예측할 수 없었고, 현재도 이 코드의 실행 결과를 이해하지 못하는 경우가 대부분이다. 차근 차근 공부해서 왜 이런 결과를 나타내는지 이해하게 된다면 다시 포스팅을 하도록 하겠다 ;)<br />
<br />
<br />Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com0tag:blogger.com,1999:blog-4567551370435954890.post-70007496627992498392013-10-22T21:40:00.000-07:002013-10-22T21:40:14.190-07:00[Unity] Jenkins로 유니티 자동 빌드 세팅하기 (4) - ios 앱 코드 사이닝<br />
이전 포스트들을 통해 살펴본 Jenkins에서 유니티 프로젝트를 빌드하는 과정을 다시 한번 정리하면 다음과 같다.<br />
<br />
<ol>
<li>Jenkins 설치</li>
<li>Jenkins 실행 계정 변경</li>
<li>Jenkins plugin 설치 및 설정</li>
<li>Git repository 접근 설정</li>
<li>Unity 빌드 스크립트 작성</li>
<li>Jenkins build job 생성</li>
<ol>
<li>Source code Management 세팅</li>
<li>Unity3d 빌드 세팅</li>
<li>Xcode 빌드 세팅</li>
</ol>
</ol>
<div>
여기까지 iOS앱을 빌드할 수 있는 과정은 모두 커버하였다. 하지만 빌드만 해서는 앱을 배포할 수는 없다. 이번 포스트에서는 빌드된 앱을 배포할 수 있도록 코드 사이닝하는 과정을 커버하고 다음 포스트에서 Testflight이라는 앱배포 서비스를 사용한는 방법을 알아 보도록 하자.</div>
<div>
<br /></div>
<div>
이전 튜토리얼까지 잘 따라왔다면 Jenkins는 git repository에서 프로젝트 파일을 가져와서 해당 빌드잡을 위한 workspace 디렉토리를 생성하고 그 안에 프로젝트 소스와 빌드 파일들을 보관하고 있을 것이다.<br />
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAa6tMuxfg9TkPYHhE1Vy6DMB8XLPgSkx9V9ZOlH0B15IH-hu71FxK4kFnszOAqmcZVNeSlfCd5iRxhP0OMKbMkSH8RAnWhDdFdaaG3OsEmXmPkpf29nMR2OCPohREZ2sxeT5j_VjYHBc/s1600/Screen+Shot+2013-10-22+at+4.15.42+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAa6tMuxfg9TkPYHhE1Vy6DMB8XLPgSkx9V9ZOlH0B15IH-hu71FxK4kFnszOAqmcZVNeSlfCd5iRxhP0OMKbMkSH8RAnWhDdFdaaG3OsEmXmPkpf29nMR2OCPohREZ2sxeT5j_VjYHBc/s640/Screen+Shot+2013-10-22+at+4.15.42+PM.jpg" width="640" /></a></div>
<div>
<br />
<br /></div>
<div>
원래 Xcode에서 배포를 위한 프로젝트 빌드를 할 때는 배포 버전의 코드 사이닝을 위해 애플 개발자 센터에서 키페어를 요청하고 app id를 등록하고 Distribution provisioning profile을 만드는 과정을 거쳐야 하는데 이 부분에 관련해서는 <a href="http://comeddy.wordpress.com/2010/10/06/ios-provisioning-portal-%EC%95%84%EC%9D%B4%ED%8F%B0%EC%97%90-%EC%95%B1-%EC%98%AC%EB%A6%AC%EA%B8%B0-%EC%A0%95%EB%A6%AC/" target="_blank">다른 블로그의 글</a>을 참고하기를 바란다.</div>
<div>
<br /></div>
<div>
Provisioning profile을 생성했다고 가정하고 다음으로 진행하도록 하자.</div>
<div>
<br /></div>
<h3>
Xcode에서 Code Signing Identity 지정하기</h3>
<div>
<br /></div>
<div>
Jenkins의 현재 작업중인 빌드 프로젝트 workspace내에 유니티의 iOS 버전 빌드로 생성된 Xcode Project 디렉토리에서 Unity-iPhone.xcodeproj 를 클릭하여 Xcode를 열도록 한다.</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigBCLSqJrb9rDCd9NVliK6uaJtt59dHv2lHcSbvCEQVHt7fpym57BTK4nDwf2GWLPfkTw2KtruGaLUd2DT2-xnm7Ao07SQrjRRFwPe-EtPZgnPAM7p59ZooFrE2MYAmAyev9uvZcke6iA/s1600/Screen+Shot+2013-10-22+at+4.47.02+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigBCLSqJrb9rDCd9NVliK6uaJtt59dHv2lHcSbvCEQVHt7fpym57BTK4nDwf2GWLPfkTw2KtruGaLUd2DT2-xnm7Ao07SQrjRRFwPe-EtPZgnPAM7p59ZooFrE2MYAmAyev9uvZcke6iA/s400/Screen+Shot+2013-10-22+at+4.47.02+PM.jpg" width="295" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
Xcode의 Project Navigator에서 최상단 프로젝트를 선택하면 Project Info 화면이 Xcode 가운데에 나타난다. 여기서 새로운 Build configuration을 추가하자. "+" 버튼을 누르고 "Duplicate "Release" Configuration"을 선택하면 된다. </div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8171sQJfLYu9CJly2SRGKShDAV9SqAw87NdjTorj6ytUYT0xslcKiTLLVtYfK-HyWbfxZzpMXTw3IGEqHAZdpPfRrt4hWw2wMlSoPribt83nBuyqlEXONVwTHB6qH1vnJNtBAwLuZ4GM/s1600/Screen+Shot+2013-10-22+at+4.51.13+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="358" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8171sQJfLYu9CJly2SRGKShDAV9SqAw87NdjTorj6ytUYT0xslcKiTLLVtYfK-HyWbfxZzpMXTw3IGEqHAZdpPfRrt4hWw2wMlSoPribt83nBuyqlEXONVwTHB6qH1vnJNtBAwLuZ4GM/s640/Screen+Shot+2013-10-22+at+4.51.13+PM.jpg" width="640" /></a></div>
<div>
<br /></div>
<div>
지금 단계에서는 앱스토어 배포가 아닌 Ad hoc 배포를 위한 빌드가 필요하므로 "Ad hoc"이라고 이름을 붙였다. 그리고 상단의 Build Settings 를 클릭하고 아래의 "Ad hoc" configuration의 "Code Signing Identity"를 발급받은 배포용 인증서로 변경한다. 앞서 애플 개발자 센터에서 인증서와 Provisioning Profile을 발급 받고 등록을 했다면 여기서 변경할때 선택할 수 있을 것이다.</div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuuXVmpMzEnp8uCLRavQe1iGXg6NRBQkCeEn89JRRRAc19boYb5xpRemi_mwIN381BtcZIIFiGSqK6IRJfG2J4V139Y7BO3BD08ZnKG9ftkF4dnD2lxn6y_1nrSs5Sx2UeFBzEcWHRuAo/s1600/Screen+Shot+2013-10-22+at+4.53.16+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="374" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhuuXVmpMzEnp8uCLRavQe1iGXg6NRBQkCeEn89JRRRAc19boYb5xpRemi_mwIN381BtcZIIFiGSqK6IRJfG2J4V139Y7BO3BD08ZnKG9ftkF4dnD2lxn6y_1nrSs5Sx2UeFBzEcWHRuAo/s640/Screen+Shot+2013-10-22+at+4.53.16+PM.jpg" width="640" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
이제 상단의 Build&Run버튼 옆의 Unity-iPhone이라고 적힌 부분을 눌러 "Edit Scheme" 다이얼로그를 오픈한다. 그리고 Archive부분을 아래와 같이 설정하도록 하자.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-5qzWaNaw6_A/UmdQHbNh8xI/AAAAAAAAEvw/Eq6Yceq9ZOM/s1600/Screen+Shot+2013-10-22+at+5.11.46+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="271" src="http://2.bp.blogspot.com/-5qzWaNaw6_A/UmdQHbNh8xI/AAAAAAAAEvw/Eq6Yceq9ZOM/s400/Screen+Shot+2013-10-22+at+5.11.46+PM.jpg" width="400" /></a></div>
<br /></div>
<div>
<br /></div>
<div>
이제 프로젝트를 저장하고 Xcode를 닫는다. 닫기 전에 Xcode 상단 메뉴의 Product -> Archive를 선택하여 Archiving이 제대로 되는지 확인해보는 것도 좋겠다.</div>
<div>
<br /></div>
<h3>
Xcode 변경 사항이 유지되도록 Unity 빌드 스크립트 수정</h3>
<div>
<br /></div>
<div>
앞 단계에서 Xcode 프로젝트에 새로운 Build Configuration을 추가하였고 이제 남은 것은 Jenkins에서 Xcode 빌드를 수행할때 해당 Build configuration으로 빌드가 되도록 하기만 하면 된다. </div>
<div>
<br /></div>
<div>
그러나 여기서 생기는 이슈는 현재 Xcode Project는 Unity에서 빌드 할 때 생성되는 것이므로 미리 위와 같은 설정을 넣어서 Source code repository에 저장할 수가 없다는 것과 Jenkins에서 해당 빌드 프로젝트를 빌드할 떄 마다 Xcode Project는 삭제되고 Unity에서 새로이 생성된다는 점이다.</div>
<div>
<br /></div>
<div>
이 문제를 해결해보자. 다시 원래의 Unity 프로젝트 소스코드를 열어 Build 스크립트를 아래와 같이 수정한다. </div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<pre class="brush:csharp">using UnityEngine;
using UnityEditor;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
class ProjectBuilder {
static string[] SCENES = FindEnabledEditorScenes();
static string TARGET_DIR = "build";
[MenuItem ("Custom/CI/Build iOS Debug")]
static void PerformiOSDebugBuild ()
{
BuildOptions opt = BuildOptions.SymlinkLibraries |
BuildOptions.Development |
BuildOptions.ConnectWithProfiler |
BuildOptions.AllowDebugging |
BuildOptions.Development |
BuildOptions.AcceptExternalModificationsToPlayer;
PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;
PlayerSettings.iOS.targetOSVersion = iOSTargetOSVersion.iOS_4_3;
PlayerSettings.statusBarHidden = true;
char sep = Path.DirectorySeparatorChar;
string buildDirectory = Path.GetFullPath(".") + sep + TARGET_DIR;
string BUILD_TARGET_PATH = TARGET_DIR + "/ios";
Directory.CreateDirectory(BUILD_TARGET_PATH);
GenericBuild(SCENES, BUILD_TARGET_PATH, BuildTarget.iPhone, opt);
}
private static string[] FindEnabledEditorScenes() {
List<string> EditorScenes = new List<string>();
foreach(EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
if (!scene.enabled) continue;
EditorScenes.Add(scene.path);
}
return EditorScenes.ToArray();
}
static void GenericBuild(string[] scenes, string target_path, BuildTarget build_target, BuildOptions build_options)
{
EditorUserBuildSettings.SwitchActiveBuildTarget(build_target);
string res = BuildPipeline.BuildPlayer(scenes, target_path, build_target, build_options);
if (res.Length > 0) {
throw new Exception("BuildPlayer failure: " + res);
}
}
}
</pre>
<!-- 애드센스 링크광고-->
<div style="text-align: center;">
<script async="" src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
<!-- tistory-la-stranger-link-horizontal-short -->
<br />
<ins class="adsbygoogle" data-ad-client="ca-pub-1146719439797488" data-ad-slot="8493677561" style="display: inline-block; height: 15px; width: 468px;"></ins><script>
(adsbygoogle = window.adsbygoogle || []).push({});
</script>
</div>
<div>
<br />
앞에서 보았던 스크립트 코드와 똑같은것 같은데 딱 한가지 바뀐것은 BuildOptions에 BuildOptions.AcceptExternalModificationsToPlayer 옵션을 추가한 것이다. 이 옵션의 의미는 Unity에서 프로젝트를 iOS버전으로 빌드할때 현재 이미 빌드된 프로젝트 파일들이 있을 경우 Replace하지 말고 Merge하라는 의미이다. 따라서 이 옵션을 추가함으로써 윗단계에서 프로젝트 파일을 수정한 내용이 사라지지 않고 남아 있을 수 있다.<br />
<br />
그러나 문제는 가장 처음 유니티에서 빌드 할 때 위의 옵션을 추가하고 스크립트를 실행하여 빌드하려고 하면 에러가 발생한다. 이유는 Merge할 대상이 없기 때문이다. 개인적인 의견으로는 유니티에서 좀 더 스마트하게 체크해서 없으면 일반 적인 빌드로 프로젝트 파일들을 만들어 낼 수 있게 되었으면 더 좋았을 텐데 아쉽다.<br />
<br />
어쨋든 위와 같이 유니티 빌드 스크립트를 수정하고 git에 commit하고 push하여 중앙 소스 저장소에 수정내용이 반영되도록 한다. 그래야 다음번 Jenkins빌드 Job이 시작될때 수정된 빌드 스크립트가 사용되고 Jenkins workspace에서 변경한 Xcode프로젝트가 초기화되지 않는다.<br />
<br />
<h3>
Jenkins Xcode plugin 설정 수정 및 빌드</h3>
<div>
자 이제 거의 마지막 단계이다. Jenkins workspace 내의 Xcode 프로젝트를 수정하여 원하는 인증서로 코드 사이닝이 될 수 있도록 Build configuration을 새로 생성하였다. 이제 Jenkins Xcode plugin이 빌드 할때 해당 Build Configuration을 사용하도록만 설정하면 된다.<br />
<br />
Jenkins build job의 Configuration을 아래와 같이 수정하도록 하자.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU-uoZWXT2fLfThwYhaOSHbimXnosGmGYlfiLOm8qMFnaD6Wy1h9KnZ2D9-abUpFvIhyNS8962xyf0okL-1vRTXfkDihtSGeiPulhlotANUV8MlOV18nL6hsxeXwYOc0axGB38u837s90/s1600/Screen+Shot+2013-10-22+at+6.05.37+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="206" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU-uoZWXT2fLfThwYhaOSHbimXnosGmGYlfiLOm8qMFnaD6Wy1h9KnZ2D9-abUpFvIhyNS8962xyf0okL-1vRTXfkDihtSGeiPulhlotANUV8MlOV18nL6hsxeXwYOc0axGB38u837s90/s640/Screen+Shot+2013-10-22+at+6.05.37+PM.jpg" width="640" /></a></div>
<br />
<br />
이렇게 설정하고 Jenkins build job을 실행하고 Console log를 확인해보면 설정된 Build configuration으로 빌드가 완료되었음을 확인할 수 있다.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsOlCRWXvm-CaSy0keaCfjXKrMlMCnWquA7o5sLLJSxHHduXEPUe8dZG_soyxFwvRHdk_HoU_nIsRD6PxN2a6ZwYl75LieoBRrTNvJGQgfUMRJSoBWQ9g8OMT5sqxJ_JiWAf8S9KvNS9c/s1600/Screen+Shot+2013-10-22+at+6.09.00+PM.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="72" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsOlCRWXvm-CaSy0keaCfjXKrMlMCnWquA7o5sLLJSxHHduXEPUe8dZG_soyxFwvRHdk_HoU_nIsRD6PxN2a6ZwYl75LieoBRrTNvJGQgfUMRJSoBWQ9g8OMT5sqxJ_JiWAf8S9KvNS9c/s640/Screen+Shot+2013-10-22+at+6.09.00+PM.jpg" width="640" /></a></div>
<br />
<br />
이상으로 iOS 앱이 원하는 인증서로 코드 사이닝되어 빌드 되는 과정을 알아 보았다.<br />
<br />
다음에는 Testflight이라는 서비스를 이용해서 팀원혹은 테스터들에게 Ad hoc빌드된 앱을 쉽게 배포하는 방법을 알아 보도록 하겠다.<br />
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
</div>Cromithttp://www.blogger.com/profile/07129537827996118197noreply@blogger.com1