Languages/Python2014.12.11 08:59

super를 사용해 multiple inheritance를 구현하다 보면, 다른 언어와는 다른 특성을 발견하게 됩니다. 예제와 그 실행 결과를 보시죠.



class Mixin(object):

    

    def create(self, str):

        print str + ".t"

        

class MixinA(Mixin):


    def create(self, str):

        super(MixinA, self).create(str+".a")

        #Mixin.create(self, str)


class MixinB(Mixin):


    def create(self, str):

        super(MixinB, self).create(str+".b")

        #Mixin.create(self, str)


class Aggregate(MixinB, MixinA):


    def __init__(self):

        pass



if __name__ == "__main__":


    aggr = Aggregate()

    aggr.create('parameter')

    print Aggregate.__mro__


    


실행 결과는 다음과 같습니다. 


parameter.b.a.t

(<class '__main__.Aggregate'>, <class '__main__.MixinB'>, <class '__main__.MixinA'>, <class '__main__.Mixin'>, <type 'object'>)


즉, super 호출을 resolution하는 순서는 __mro__ 어트리뷰트에 명시된 값 순서를 따릅니다. sibling 클래스에 있는 메서드도 호출된다는 것이 중요합니다. 


물론, Mixin.create(self, str)과 같이 상위 클래스 메서드를 호출하게 되면 이런 순서는 무시되고, 같은 이름의 메서드 가운데 최초 상속된 메서드만 호출됩니다.



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/562 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Python2014.12.05 14:09


import six

import abc


@six.add_metaclass(abc.ABCMeta)

class MyAbstractClass(object):


    @abc.abstractmethod

    def abstract_method(self):

        while False:

            yield None


    def public_method(self):

        self.abstract_method()


class MyConcreteClass(MyAbstractClass):


    def abstract_method(self):

        '''

        if this method is omitted, following error is raised

        when public_method is called against an object.

        

            TypeError: Can't instantiate abstract class MyConcreteClass

            with abstract methods abstract_method


        '''

        print "abstract method is implemented."


    def __init__(self):

        pass


#

# below shows list of all the abstract methods.

#

print MyAbstractClass.__abstractmethods__

print MyAbstractClass.__mro__ # show method resolution order

print MyConcreteClass.__abstractmethods__

print MyConcreteClass.__mro__ # show method resolution order


#

# create an object of MyConcreteClass

# and call its 'public_method'.

#

entity = MyConcreteClass()

entity.public_method()


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/561 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Java2014.09.05 12:23

이펙티브 자바(Effective Java)의 2판이 다시 번역되어 재출간되었습니다. 출판사는 인사이트입니다. 





원래 대웅출판사에서 번역되어 출간되었다가 절판된 것을 이번에 인사이트에서 다시 번역해서 출간했습니다. 원래 번역본을 전혀 참고하지 않은, 전면적인 재 번역입니다. 


참고하시라고, 118페이지의 본문을 발췌해 보았습니다. 


규칙 16은 계승을 위한 설계와 문서를 갖추지 않은 “이질적(foreign)” 클래스의 하위 클래스를 만들 때 생기는 문제점을 설명하고 있다. 그렇다면 계승을 위한 설계와 문서를 갖춘다는 것은 어떤 의미일까?


우선, 메서드를 재정의하면 무슨 일이 생기는지 정확하게 문서로 남겨야 한다. 다시 말해, 재정의 가능 메서드를 내부적으로 어떻게 사용하는지(self-use) 반드시 문서에 남기라는 것이다. public이나 protected로 선언된 모든 메서드와 생성자에 대해, 어떤 재정의 가능 메서드를 어떤 순서로 호출하는지, 그리고 호출 결과가 추후 어떤 영향을 미치는지 문서로 남기라는 것이다. (재정의 가능하다는 것overridable은 public 또는 protected로 선언된 비-final 메서드라는 뜻이다.) 좀 더 일반적으로 이야기하자면, 재정의 가능 메서드가 호출되는 모든 상황을 문서로 남기라는 것이다. 예를 들어, 후면(background) 스레드가 호출할 수도 있고, static 초기화 구문(initializer) 안에서 호출할 수도 있다.


관습적으로, 재정의 가능 메서드를 어떤 식으로 호출하는지는 메서드 주석문 마지막에 명시한다. 주석은 “이 구현은”이라는 문구로 시작한다. 릴리스에 따라서 달라질 수 있다는 뜻으로 하는 말은 아니며, 메서드 내부 동작 원리에 관한 주석이라는 뜻이다. 아래에 java.util.AbstractCollection 명세에서 가져온 예제를 보였다.


170페이지, 규칙 26 관련 본문도 한번 보겠습니다.


컴파일러는 프로그램의 형 안전성을 입증할 수 없을지 모르지만, 프로그래머는 할 수 있다. 무점검 형변환(unchecked cast)을 하기 전에 개발자는 반드시 그런 형변환이 프로그램의 형 안전성을 해치지 않음을 확실히 해야 한다. 위에서 문제가 되고 있는 배열 elements는 private 필드이고 클라이언트에 반환되지 않으며 다른 어떤 메서드에도 전달되지 않는다. push 메서드에 전달되는 원소만이 배열에 저장되며, 그 타입은 전부 E다. 따라서 무점검 형변환을 해도 아무런 문제가 없다.


무점검 형변환이 안전함을 증명했다면, 경고를 억제하되 범위는 최소한으로 줄여야 한다(규칙 24). 위의 예제의 경우, 생성자에 있는 코드라고는 무점검 배열 생성을 하는 코드가 전부이므로 생성자 전체적으로 경고를 억제해도 무방하다. 경고를 억제하는 어노테이션을 추가하고 나면 Stack 클래스는 아무 문제없이 컴파일 될 것이며, 명시적인 형변환이나 ClassCastException이 발생할 걱정없이 사용할 수 있게 된다.


Java 1.8이 공개된 시점이지만, 이 책의 많은 부분은 아직도 유효한 교훈들을 담고 있습니다. 최신 Java와 많이 달라진 부분에는 제한적이지만 주석이 달려 있어서, 1.8에서 해결된 것이 무엇인지 살펴볼 수 있도록 약간의 배려도 하고 있습니다.


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/559 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 지나가던개발자

    예로 보여주신, Item17대목요...

    Inheritance를 계승이라 번역하시고, foreign class를 '이질적 클래스'라고 하셨는데..
    inheritance는 이제 '상속'이라는 말로 통용되고,
    foreign class는 이전 아이템(16)의 주제를 보면 '패키지 외부의 클래스' 정도로 이해되는데..

    다른 의도가 있으셨던 건가요?

    2014.09.22 15:19 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 내가 설계하지 않은 클래스라는 의미를 좀 더 잘 전달할 용어를 찾았던 것인데, 지금 다시 살펴보니 좀 오버한 것 같기도 합니다. 그래서 가급적이면 영어 원문을 병기하였사오나, 혼란이 있으셨다면 사과드립니다.

      2014.09.24 11:54 신고 [ ADDR : EDIT/ DEL ]

Languages/Java2014.08.04 23:44

Java 1.8부터 ::를 통한 메서드 참조가 가능하기 때문에 (이런 참조는 전부 Functional 계열의 인터페이스를 통해 처리됩니다) 자료형 토큰 (MyClass.class 같은 것들) 사용을 줄일 수 있습니다. 


다음의 enum 자료형 예제를 보시죠. 각 상수에 해당 상수가 나타내는 Mode의 객체를 반환하는 기능이 들어 있는데, 자료형 토큰 없이도 생성자를 넘기고, 해당 생성자에 따라 객체를 만들 수 있습니다.


생성자는 Supplier<T> 인터페이스를 통해 참조할 수 있습니다. 이 인터페이스는 T get() 메서드를 가지고 있습니다. 


interface Encoder {

void init();

void setQuality(int quality);

int getFrameSize();

void encode(Bits bits, float[] data);

}


class NarrowBandEncoder implements Encoder {

@Override

public void init() {

// whatever

}


@Override

public void setQuality(int quality) {

// TODO Auto-generated method stub

}


@Override

public int getFrameSize() {

// TODO Auto-generated method stub

return 0;

}


@Override

public void encode(Bits bits, float[] data) {

// TODO Auto-generated method stub

}

}


class WidebandEncoder implements Encoder {

@Override

public void init() {

// whatever

}


@Override

public void setQuality(int quality) {

// TODO Auto-generated method stub

}


@Override

public int getFrameSize() {

// TODO Auto-generated method stub

return 0;

}


@Override

public void encode(Bits bits, float[] data) {

// TODO Auto-generated method stub

}

}


class UltraWidebandEncoder implements Encoder {

@Override

public void init() {

// whatever

}


@Override

public void setQuality(int quality) {

// TODO Auto-generated method stub

}


@Override

public int getFrameSize() {

// TODO Auto-generated method stub

return 0;

}


@Override

public void encode(Bits bits, float[] data) {

// TODO Auto-generated method stub

}

}


enum EncodingMode {

NARROW_BAND(NarrowBandEncoder::new),

WIDE_BAND(WidebandEncoder::new),

ULTRA_WIDE_BAND(UltraWidebandEncoder::new);

private Supplier<? extends Encoder> encoder;

private EncodingMode(Supplier<? extends Encoder> supplier) {

this.encoder = supplier;

}

public Encoder createEncoder() {

return this.encoder.get();

}

}



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/557 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 잘 보고 갑니다. 오늘도 활기찬 하루 되시길요. ^^

    2014.08.04 23:54 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Java2014.06.13 23:41

그런데 이 밤중에 저는 왜 이런 짓을 하고 있는 걸까요? (수줍)



/*

 * Source.java

 */

final class Source {


private final int[] array;

private int index;

Source(int[] array) {

this.array = array;

this.index = 0;

}

static Source min(Source a, Source b) {

if ( a.index < a.array.length && b.index < b.array.length ) {

if ( a.array[a.index] < b.array[b.index] ) {

return a;

} else {

return b;

}

} else if ( a.index >= a.array.length ) {

return b;

} else {

return a;

}

}

int getValue() {

return this.array[this.index];

}


void advanceIndex() {

++this.index;

}

boolean isEmpty() {

return ( this.index >= this.array.length );

}

}


/*

 * Main.java

 */

import java.util.Arrays;

import java.util.Random;


public class Main {

private static Random generator = new Random();

private static int[] getSortedArray(int length) {

int[] ret = new int[length];

for ( int i = 0; i < length; ++i ) {

ret[i] = generator.nextInt(1000);

}

Arrays.sort(ret);

return ret;

}

public static int[] threeWayMergeSort(int[] a, int[] b, int[] c) {

Source one = new Source(a);

Source two = new Source(b);

Source three = new Source(c);

int[] ret = new int[a.length + b.length + c.length];

int retIndex = 0;

while ( !one.isEmpty() || !two.isEmpty() || !three.isEmpty() ) {

Source min = Source.min(one, Source.min(two, three));

ret[retIndex++] = min.getValue();

min.advanceIndex();

}

return ret;

}

public static void main(String[] args) {

int[] a = getSortedArray(100);

int[] b = getSortedArray(100);

int[] c = getSortedArray(100);


int[] result = threeWayMergeSort(a, b, c);


                for ( int i = 0; i < result.length; ++i ) {

System.out.printf("%4d ", result[i]);

if ( ((i+1)%10)==0 ) System.out.println();

}

}

}


이런거 짜보라고 했는데 칠판에 코드 못 그렸으면 열좀 받았겠죠? 네 그래서 한번 해봤습니다 ㅎㅎ 사실 면접 볼때 이런 유형의 문제가 나오면 제일 먼저 드는 생각은 "이거 못풀면 진짜 개망신이겠군..." 이죠 (발그레) 그러다 진짜 못풀면 하루 종일 잠이 안온다능...

저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/551 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Python2014.01.01 11:42

1. 다양한 기능을 갖춘 언어가 필요하다면 


"실용주의 프로그래머(Pragmatic Programmer)"라는 책을 보면 일년에 하나 정도의 새 언어를 배우라는 조언이 있어요. Peter Norvig라는 사람이 쓴 "Teach Yourself Programming in Ten Years"라는 에세이를 봐도, 적어도 여섯 개의 "종류가 서로 다른" 언어를 10년간 배우라는 조언이 있지요. 뒤집어 이야기하면, 세상에는 여섯 가지 부류의 언어가 있다는 이야긴데요. 대충 정리해보면 다음과 같습니다. 


http://www.smallanimaltalk.com/2013/04/worlds-cutest-python.html


(1) 클래스 추상화(class abstraction)를 제공하는 언어

(2) 함수형 추상화(functional abstraction)를 제공하는 언어 

(3) 문법 추상화(syntactic abstraction)을 지원하는 언어 

(4) 선언적 명세(declarative specification)를 지원하는 언어

(5) 코루틴(coroutine)을 지원하는 언어 

(6) 병렬수행(Parallelism)을 지원하는 언어 


다른건 잘 모르겠고 (1), (2), (5)는 지원되면 좋겠다고 생각하는데요. 객체지향 언어는 이미 업계 대세니까 당연한거고, 함수형 추상화는 요즘 유행인데다 거의 모든 언어가 함수형 추상화를 지원하기 위해 삽질중이라 더더욱 그렇죠. Python은 (1), (2), (5)를 지원합니다. 객체지향 언어이자, 함수형 프로그래밍 언어이기도 하죠. 파이썬의 함수와 함수형 프로그래밍에 대해서는 http://docs.python.org/2/howto/functional.html 이 문서를 참고하면 좋겠습니다. 


사실 위의 여섯가지 속성을 거의 전부 만족시키는 언어도 있긴 한데요. Python의 미래라고 보는 사람도 있는 Julia입니다. http://julialang.org/ 


SEE ALSO: Java를 배워야 할 다섯가지 이유

SEE ALSO: 새로운 언어를 더 빨리 배우려면?


2. 생산성이 중요하다면


Python과 다른 언어의 성능을 비교하는 논쟁은 다양하게 있어 왔습니다. 한 가지 얻을 수 있는 결론은, Python의 성능이 나쁘지 않다는 겁니다. http://stackoverflow.com/questions/672857/is-python-slower-than-java-c 하지만 우리가 언어를 선택하는 기준이 꼭 성능 뿐만인 것은 아니죠. Python의 가장 큰 장점은 생산성입니다. https://pythonconquerstheuniverse.wordpress.com/2009/10/03/python-java-a-side-by-side-comparison/ 물론 어떤 언어의 생산성을 단순히 언어의 문법적인 측면만으로 논하는 것은 좀 위험한 일이긴 합니다만, Python의 문법이 보다 간결한 프로그래밍을 가능케 하는 것은 사실입니다. 


3. 프로그래밍 습관을 고치고 싶다면


파이썬은 들여쓰기(indentation)로 프로그래밍을 하는 드문 언어 가운데 하나입니다. C/C++/Java 등의 일반적인 프로그래밍 언어들은 보통 {와 }를 사용해서 구문의 범위를 구별하죠. 들여쓰기로 프로그래밍을 하면 {와 }를 쳐 넣지 않아도 되니까 프로그래밍 하기가 좀 편해지긴 하겠습니다만 코드가 길어지면 가독성이 점차로 떨어지게 되는 문제도 있습니다. 대체 어디서부터 어디까지가 함수인지를 명확하게 알기 어렵다는 문제도 있죠. 


그래서 파이썬으로 프로그래밍을 하다 보면 의식적으로 함수 하나의 길이를 줄이게 되는데요. (너무 길어지면 정말 정신 사나워지거든요.) 그러다보면 코드는 좀 더 테스트하기 쉬운 단위로 분할되죠. 이런 종류의 리팩터링(refactoring)을 의식적으로 하게 된다는 것은, 프로그래밍을 처음 배우는 사람 뿐 아니라 프로그래밍을 굉장히 오랫동안 해 온 사람에게도 유익한 것이죠. (Python 프로그램의 가독성이 다른 프로그램보다 높다는 사람이 있는데요. 아마 이런 종류의 반강제적 리팩터링과 간결한 문법 덕분에 그런 주장이 가능한 것이 아닐까 생각합니다.)


4. 초대형 프로젝트에 사용되는 dynamic 언어를 배우고 싶다면 


Python은 초대형 프로젝트에서 널리 사용되고 있는 동적 프로그래밍 언어이기도 합니다. http://www.ozytive.com/2012/10/13/10-reasons-why-you-should-learn-python/ 그러니, 초대형 프로젝트를 진행할만한 여력이 있는 회사에 취직하고 싶다면, Python을 알아두는 것이 좋겠어요. 이런 것은 단순히 프로그래밍 언어 유행을 따라가느냐 마느냐의 문제는 아니죠. 


5. 배우기 쉬운 dynamic language가 필요하다면


Python은 분명 배우기 쉬운 dynamic language입니다. 거기다 거대한 개발자 커뮤니티를 갖고 있죠. (Python의 역사는 꽤 오래 되었습니다.) 거기다 문서화도 충실하게 잘 되어 있어서, 아주 쉽게 배울 수 있는 언어이기도 합니다. (아마 기본적인 문법서 한권 정도를 본 다음 doc.python.org의 HOWTO 문서를 읽으면 바로 프로그래밍을 시작하실 수 있을 겁니다. 저는 일주일 걸렸습니다.) 


이것은 Python의 기본적인 문법이 기존 프로그래밍 언어와 크게 다르지 않기 때문이기도 하고, 가능한 자연어에 가깝게 느껴지는 문법적 구조를 채택하고 있기 때문이기도 합니다. Julia는 이점에서 Python과는 좀 다릅니다. 코드를 보면, 뭘 하는 코드인지 한 눈에 확 들어오질 않아요. (물론 다르게 생각하시는 분들도 있긴 하겠습니다만. :-P)



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/530 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 블로그 내용 잘 보고 갑니다.

    2014.01.01 15:14 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 파이썬에 대해 다시금 바라보게 되는 좋은 글이네요. 특히나 6가지 항목이 가장 눈길을 끄는군요. 파이썬 책을 하나 사봐야겠는데요.

    2014.11.18 09:14 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Java2013.12.31 11:56

1. Garbage Collection이 필요하다면


메모리 할당/반환을 처리하는 것이 너무 지겹고 고단하다면, Java를 배워야 할 필요가 있을지 모릅니다. 잘 잘려진 대로, Java는 메모리 할당과 반환에 대한 작업을 Garbage Collector를 통해 알아서 처리해 줍니다. 그 성능이 걱정되신다구요? Java는 만들어진 지 오래된 언어이고, JVM의 성능을 최적화하기 위해 오랫동안 애써 왔습니다. 그 이야기는, Java의 JVM이 제공하는 Garbage Collector의 성능이 이제 믿을만한 수준까지 도달했다는 의미이기도 합니다. (물론 Java에서도 메모리 누수 현상, 즉 Memory Leak은 발생할 수 있으므로 이를 피하기 위해서는 코딩할 때 주의해야 합니다. Effective Java 2nd Edition을 참고하세요.) 


물론 잘 최적화된 C/C++ 바이너리와의 성능을 비교하는 것은 어불성설입니다. 하지만 C++로 작성한다고 무조건 성능이 더 나을거라는 생각은 버리는 것이 좋습니다. 대체적으로, 높은 성능을 내는 것은 무슨 무슨 언어를 쓴다고 공짜로 따라오는 것이 아니라, 프로그래머의 노하우, 패턴, 최적화 등등이 함께 결합되어야 가능하기 때문입니다. 


http://neuroph.sourceforge.net/index.html



2. 어떤 라이브러리를 쓸까 고민하기 싫다면


Java에는 이미 굉장히 큰 규모의 라이브러리가 번들링되어 있습니다. 이 라이브러리들만 잘 사용해도 대다수의 작업은 무리없이 처리할 수 있습니다. 게다가, 관련된 오픈소스 프로젝트들도 많아서, 용도에 맞는 써드 파티 라이브러리를 선택할 때 자유도가 굉장히 높습니다. '무슨 무슨 일을 하는 라이브러리는 파이썬이나 C++ 밖에 없어요. 그러니 우리는 프로젝트를 C++로 진행해야...'와 같은 상황이 생길 여지가 별로 없다는 것이죠. 


굳이 예를 하나 들자면.... 여러분은 GPU 코어를 사용해 시스템 처리 성능을 높이는 방법론인 CUDA를 알고 계실 겁니다. 예전 같으면 이처럼 시스템에 아주 가깝게 다가가 있는 기능을 사용하는 프로그램을 작성할 때 C/C++ 말고는 선택할 수 있는 언어가 거의 없었겠지만, 이제 자바 사용자는 JCUDA(http://www.jcuda.org/)를 사용해서 CUDA 프로그래밍을 할 수 있습니다. 


3. 높은 이식성이 필요하다면


JVM마다 성능이 조금씩 달라지는 일은 있습니다만, 대체로 Java 프로그램의 이식성은 JVM에 의해 보장됩니다. Java 표준을 충실히 따르는 프로그램을 개발했다면, 거의 모든 플랫폼에서 재컴파일 없이도 프로그램을 돌릴 수 있습니다. 아, 물론 Microsoft VM을 사용하는 프로그램을 짰다면 그것은 예외. (묵념) 


4. 수평적 규모 확장성이 요구된다면


Hadoop을 아십니까? 이제 데이터 처리에 있어 수평적 규모확장성(horizontal scalability)이 필요할 때, Hadoop 기반의 플랫폼은 무슨 업계 표준인 것 처럼 받아들여지고 있는 실정이죠. 놀라운 것은, Hadoop이라는 플랫폼이 Java로 작성되어 있다는 것입니다. 그 말은, 시스템에 요구되는 높은 확장성을 달성할 때 중요한 것이 더 이상 언어가 아니라는 점이며, Java가 그러한 성능 요구사항을 달성할 수 있는 수준으로 진화했다는 사실입니다. 어쨌든, Hadoop이 필요하다면 여러분은 Java를 배우는 것이 좋습니다. 물론 다양한 언어 바인딩(binding)들이 나오고 있는 실정이지만 말이죠. 


물론 수평적 규모 확장성을 달성하는 방법이 Hadoop만 있는 것은 아닙니다. Hazelcast(http://www.hazelcast.com/)도 한번 구경해 보세요. Java 기반의 미들웨어가 어디까지 진화해 있는지 느끼실 수 있을 겁니다.


5. 좀 더 편하게 개발하고 싶다면 


Java 개발자들에게 있어서 Eclipse란 어떤 존재인가요? (물론 요즘은 C++/Python 등 다양한 언어의 개발 환경도 Eclipse로 통합되고 있는 실정이긴 합니다만.) 아마 대다수의 Java 개발자는 (저 포함) Eclipse 없는 개발은 상상도 하지 못할지 모르겠군요. 이 놀라운 IDE 덕분에, Java 개발자들의 개발 생산성은 vi로 코딩하고 Make로 빌드하던 초창기에는 상상도 할 수 없을 차원으로 높아졌습니다. 


게다가 여러분은 지금, Android 개발 까지도 진행할 수 있을 만큼 진보된 Eclipse를 사용하고 있습니다. 게다가 Marketplace 기능을 통합한 Eclipse는, 새로운 개발 지원 기능의 통합을 믿을 수 없을 만큼 신속하게 수행할 수 있도록 해주죠. Eclipse는 Java 개발자들의 생산성을 높여줄 뿐 아니라, Java 언어에 대한 진입 장벽 또한 낮추고 있습니다. 


SEE ALSO: 파이썬(Python)을 배워야 할 다섯가지 이유



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/529 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 비밀댓글입니다

    2013.12.31 18:22 [ ADDR : EDIT/ DEL : REPLY ]
  2. 어? 왜 비밀글이 되었지??

    2013.12.31 18:23 신고 [ ADDR : EDIT/ DEL : REPLY ]
    • 항상 좋은 글 잘 보고있습니다. 이번 주제는 JAVA의 필요성에 대해 말씀해 주셨는데요 위와같은 사항으로 고민중인 C/C++ 프로그래머라면 개인적인 소견이지만 JAVA보다는 C#도 어떨까 싶습니다.
      1) 자동화된 메모리관리
      2) JAVA와 유사한 라이브러리들과 MSDN
      3) C/C++과 유사한 문법
      4) C/C++의 dll링크가 가능 (C++의 속도와 C#의 편의성 두 이득을 동시에...)
      5) 윈도우 뿐 아니라 리눅스에도 모노를 통해 점점 확장성이 생기고 있음
      6) 스마트폰 게임을 개발중이라면 유니티에서 제공하는 기본 언어(물론 자바도 가능하지만 C#쪽이 더 낫다더군요.. JAVA쪽 유니티는 경험하지 못했습니다.)
      ---
      코멘트 해주신 내용 다시 붙였습니다. 감사합니다.

      2013.12.31 18:38 신고 [ ADDR : EDIT/ DEL ]

Languages/Python2013.09.30 16:44

이 방법은 http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python에 공개된 방법입니다. 아래에는 결과만 보여드립니다. 


import itertools
def erat2( ):
    D = {  }
    yield 2
    for q in itertools.islice(itertools.count(3), 0, None, 2):
        p = D.pop(q, None)
        if p is None:
            D[q*q] = q
            yield q
        else:
            x = p + q
            while x in D or not (x&1):
                x += p
            D[x] = p


이 함수를 실행하는 함수를 다음과 같이 정의합니다. 


def get_primes_erat(n):
  return list(itertools.takewhile(lambda p: p<n, erat2()))


실행해 보면 다음과 같은 결과를 얻습니다. 


>>> get_primes_erat(1000)

[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73,

 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163

, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251

, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349

, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443

, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557

, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647

, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757

, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863

, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983

, 991, 997]

>>>


제일 신속한 방법이라고 알려져 있습니다. 



저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/474 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Python2013.09.27 16:30

파이썬 프로그래밍을 하다보면 가끔 'NoneType' object is not iterable 이라는 오류를 만나게 될 때가 있습니다. 물론 이 오류 메시지는 


for i in something:

   ...


위의 코드에서 'something'이 'for'를 적용할 수 없는 객체인 경우에도 만나게 됩니다만, 가끔은 이런 경우에도 만날 수 있습니다. 가령 위의 for 문 안에서 뭔가를 한다고 해 봅시다. 


for i in something:

  ret = do_something(i)

  do_another_something(ret)


그런데 do_something() 메소드 내부 코드가 다음과 같이 구현되어 있다고 해 봅시다.


def do_something(i):

  if some_condition(i):

    return some_result_of_processing(i)


그러니까 이 메소드는 i에 대해서 어떤 조건이 만족되면 뭔가를 리턴하지만, 그 조건이 만족되지 않을 경우에는 아무것도 리턴하지 않습니다. 심지어 None 조차도 리턴하지 않고 있죠. 이런 경우에 종종 for 문 안에서 ret = do_something(i)를 하는 순간 'NoneType' object is not iterable이라는 오류가 발생하곤 합니다.


따라서 위의 do_something 함수처럼 뭔가를 반환해야 하는 함수인데, 아무것도 반환하지 않게 되는 경우가 생기지 않도록 주의해야 되겠습니다. 그렇지 않으면 오류 메시지의 뜻이 무엇인지 해석하는 데 한참 걸리게 될 수 있으니까요.




저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/473 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. guest

    python은 리턴 값이 없으면 None type을 리턴합니다. 그래서 None type은 iteration 할 수 없다고 하는 것이지요...

    2013.12.13 16:47 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages2013.09.13 11:08

요즘 통계 데이터 분석과 시각화 도구로 R이라는 언어가 각광받고 있습니다. 그러나 이 언어는 진입 장벽이 다른 언어보다 조금 높은 편인데요. 아마 시각화 관련된 부분이 큰 비중을 차지해서가 아닐까 싶습니다.


그런데 이런 부분에 대한 갈증을 해소해 줄 만한 책이 인사이트에서 나왔습니다. R Graphics Cookbook 입니다. "데이터 시각화를 위한 실용 레시피"라는 부제를 달고 나왔습니다. 




책을 읽어보지 못했으므로 내용에 대해서는 뭐라 말씀드리기 그렇습니다만, R Cookbook이라는 또다른 서적과 함께 읽으신다면 꽤 충실한 안내서 역할을 해 줄 것으로 기대합니다. 


요즘 인포그래픽스다 뭐다 해서 관련 분야가 뜨고 있는 만큼, 배워두면 좋겠죠? 이런 것도 다 그릴 수 있답니다. 








저작자 표시 비영리 변경 금지
신고

'Languages' 카테고리의 다른 글

R 언어 시각화, 어떤 책으로 배워야 할까?  (0) 2013.09.13
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/467 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Java2013.04.17 11:51

JAR file can be dynamically loaded from a running Java program. The dynamic loading is relatively easy. 


public class JarLoader {


@SuppressWarnings("unchecked")

private static Class<OFController> loadJar(String path) {

if ( !path.endsWith(".jar") ) {

// this is not a jar file.

return null;

}

String basename = Basename.get(path, "jar");

File file = new File(path);

if ( file.exists() ) {

ClassLoader loader;

try {

loader = URLClassLoader.newInstance(

new URL[] { file.toURI().toURL() },

JarLoader.class.getClassLoader()

);

return (Class<OFController>)
                                    Class.forName( basename, true, loader );

} catch (MalformedURLException e1) {

return null;

} catch (ClassNotFoundException e) {

Logger.stderr("basename " + basename + " is not found");

e.printStackTrace();

return null;

}

}

return null;

}


public static OFController getController(String path, int num_of_instances) {

Class<OFController> ctrl = loadJar(path);

if ( ctrl == null ) {

return null;

}

try { 

Constructor<OFController> constructor = 

ctrl.getConstructor(new Class[]{ int.class });

return constructor.newInstance( num_of_instances );

} catch (NoSuchMethodException e) {

Logger.stderr("Cannot find constructor for " + path);

return null;

} catch (SecurityException e) {

Logger.stderr("You are not authorized to open " + path);

return null;

} catch (InstantiationException e) {

Logger.stderr("Cannot instantiate controller from the given jar "
                                          + path);

return null;

} catch (IllegalAccessException e) {

Logger.stderr("You are not authorized to access constructor for "
                                           + path);

return null;

} catch (IllegalArgumentException e) {

Logger.stderr("You have passed wrong argument to " + path);

return null;

} catch (InvocationTargetException e) {

Logger.stderr("Wrong invocation target for " + path);

return null;

}

}

}


Above code is from a working system. Basically, all you need to look is the URLClassLoader, loadJar method, and codes  that actually call the constructor of the loaded class. 




In implementing this class, We have used a utiliy class called 'Basename'. As we set the name of the Jar file to the complete path of the class including package name (for example, xxx.yyy.SimpleClass), the class 'Basename' is critical in extracting the class name that would be instantiated. 


public class Basename {

public static String get(String path, String extension) {

String[] delimited = path.split("/");

String filename = delimited[ delimited.length - 1 ];

return filename.substring(0, filename.lastIndexOf("." + extension));

}

}


May the force of JAR files be with you!


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/462 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Java2013.04.15 11:16


Java NIO and reactor pattern.Java NIO and reactor pattern. http://www.moparscape.org/smf/index.php?topic=460976.0


The key component of java NIO is java.nio.channels.Selector. With this, you can easily monitor a specific set of events happening from underlying channels. With this, you can easily write codes to create a socket, bind the socket, listen the socket, and accept a new client connection. 


Following is an example code from a working system. 


Selector accept_selector = Selector.open();


ServerSocketChannel tcp_server = ServerSocketChannel.open();

tcp_server.socket().bind(new InetSocketAddress(6633));

tcp_server.configureBlocking(false);

tcp_server.register( accept_selector, SelectionKey.OP_ACCEPT );


//

// start accept loop

// 

int accept_seq = 0;

while ( !quit ) {

int r = accept_selector.select();


if ( r > 0 ) {

// accept set is ready

Set<SelectionKey> keys = accept_selector.selectedKeys();

for ( Iterator<SelectionKey> i = keys.iterator(); i.hasNext(); ) {

SelectionKey key = i.next();

i.remove();


if ( key.isAcceptable() ) {

int seq = ++accept_seq;

SocketChannel sw_channel = tcp_server.accept();

sw_channel.configureBlocking(false);

sw_channel.socket().setTcpNoDelay(true);

sw_channel.socket().setPerformancePreferences(0,2,3);


some_thread_object.addClient( sw_channel );

}

}

}

}



Above code is very simple, so I think no further explanation is needed. One thing to note is that you can also apply this kind of convention to the socket read. After creating sw_channel, you might pass the channel to a thread that monitors a set of connections. Then, the thread does 'select' on the set of connections, check if there are some readable connections. On the readable connections, you can actually perform 'read'. 


void addClient(SocketChannel client) {

synchronized ( guard ) {

try {

// ...

client.register( 

read_selector.wakeup(), 

SelectionKey.OP_READ | SelectionKey.OP_WRITE, 

null /* attachment */

);

} catch (ClosedChannelException e) {

// channel is closed. 

try {

client.close();

} catch (IOException e1) {

// does nothing.

}

}

}

}


Above code is to register a ClientChannel object to a 'read_selector' object, that the thread object has as its private member. One thing to note is, how the 'guard' object is used to prevent deadlock at client.register() and read_selector.select() call. This is an idiom, so please follow it. 


while ( !quit ) {

try {

// guard idiom to prevent deadlock at client.register() call

synchronized (guard) {}


int r = read_selector.select();

if ( r > 0 ) { // there's something to read.


Set<SelectionKey> keys = read_selector.selectedKeys();

for ( Iterator<SelectionKey> i = keys.iterator(); i.hasNext(); ) {

SelectionKey key = i.next();

i.remove();

try { 

if ( !key.isValid() ) {

// do something

key.cancel();

conn.close();

continue;

}

if ( key.isWritable() ) {

// do something

}

if (  key.isReadable() && !handleReadEvent(conn) ) {

// do something

key.cancel();

conn.close();

}

} catch ( CancelledKeyException e ) {

e.printStackTrace();

continue;

}

}

}

} catch (IOException e) {

e.printStackTrace();

// just break this watcher.

return;

}

}


Above codes are from the run loop of  'some_thread_object'. Basically, this loop monitors a set of channels that read and write is possible. Once the selector selected a set of keys (each key is mapped to one SocketChannel object) that are readable or writable, you should check teach channel is actually readable using key.isReadable(), or writable using key.isWritable(). If they return true, that means you are able to read from or write to the channel. 


May the NIO be with you!


저작자 표시 비영리 변경 금지
신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/461 관련글 쓰기

소중한 의견, 감사합니다. ^^

Languages/Java2011.07.12 18:45
SNMP4J: Cannot Handle InetAddress null response

SNMP4J를 사용해서 SNMP Response를 처리하다 보면, 분명히 있는 테이블의 있는 컬럼인데 그 값을 제대로 읽어오지 못하고 timeout이 나버리는 경우가 있습니다. 가령 다음 그림을 보시면...

SNMP4J library does not handle null values for InetAddress columns or scalar values. Therefore, if you do GET or GETNEXT or GETBULK for the fields, your request will be timed out. But most of the MIB browsers do not. They handle the case without error.


MIB 브라우저로 보면 InetAddress 타입의 Table Column 값이 없을 경우 null 응답을 받아서 잘 보여주고 있는 점을 보실 수 있습니다. 그런데 SNMP4J 라이브러리는 InetAddress 타입 컬럼의 값이 null인 경우를 제대로 처리하지 못합니다. 즉, InetAddress 타입 컬럼의 값이 null로 채워진 응답을 받으면, 그냥 무시해버립니다. 그러다보니 SNMP Agent에서는 응답을 보냈어도 클라이언트 쪽에서는 Timeout 나 버리는 경우가 발생하죠.

Above picture shows that MIB browsers correctly handle null-value for InetAddress fields. But, as I already tolds you, SNMP4j does not.



이 문제를 교정하려면 org.snmp4j.smi.IpAddress 클래스를 다음과 같이 수정해야 합니다.

To remedy this problem, you should fix org.snmp4j.smi.IpAddress class as follows.


이렇게 수정하고 실행해보면 이제 SNMP Agent가 InetAddress 타입 column의 값을 null로 보내도 오류 없이 처리하는 것을 보실 수 있습니다. SNMP4J는 소스코드와 함께 Maven 프로젝트 형식으로 배포되기 때문에, 간단히 재컴파일해서 쓰실 수 있습니다.

As SNMP4J is distributed as a Maven project with source codes, you can easily recompile and detour the timeout problems. :-)


신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/342 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 좋은 정보 감사합니다..ㅎㅎ 이 부분은 시행착오를 격지 않을듯..

    2013.12.11 17:20 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 그러시다니 다행입니다. :-)

    2013.12.11 17:21 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Java2011.03.14 17:04
64비트 환경에 64비트 Java SE JDK를 깔고 Android SDK를 설치하려면 제일 먼저 마주치게 되는 문제가 바로
Java SE Development Kit (JDK) not found 라는 오류 메시지.

이 오류 메시지는 말 그대로 JDK를 찾지 못하는 데서 오는 오류. 이 오류에 대한 해결책은 http://codearetoy.wordpress.com/2010/12/23/jdk-not-found-on-installing-android-sdk/ 에 가 보면 장황하게 나열 되어 있으나 그 아래 부분에도 적혀 있듯이 가장 최근에 보고된 바에 따르면 이 문제를 해결하는 최고로 단순한 해결책은...




Back 버튼을 한 번 눌렀다가 다시 Next 버튼을 누르는 것. -_-



그러면 거짓말처럼 다음으로 넘어갑니다. http://codearetoy.wordpress.com/2010/12/23/jdk-not-found-on-installing-android-sdk/ 에 제시된 Registry-based solution은 그대로 안될 경우에 적용해 보실 것.

참고로 현재 인스톨을 시도하고 있는 플랫폼은 Windows 7 64bit 플랫폼인데, 여기에 SDK를 설치한 후 다른 모든 부분이 정상동작하는 지는 테스트 한 뒤에 다시 포스팅하도록 하겟습니다.

웹을 뒤지다 보면 안드로이드 폰을 Windows 7에 USB로 연결하면 인식이 안된다는 이야기를 접하게 되는데, 같은 문제에 직면하셨다면 http://www.luismajano.com/2010/08/11/install-android-usb-drivers-windows-7-6432-bit/ 이 링크를 참고하셔서 PDANet을 설치하는 것을 고려해 보실 것. 제품에 따라 인식이 바로 될 수도 있고 안 될 수도 있습니다. 안되는 경우에만 도전해보세요.



신고
Posted by 이병준
TAG 64bit, Android, SDK

TRACKBACK http://www.buggymind.com/trackback/312 관련글 쓰기

소중한 의견, 감사합니다. ^^

  1. 우오옷~~ 탁월한 해결책입니다. ㅋㅋ

    2011.03.15 10:29 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 오우 정말 탁월합니다~ 저는 jdk 몇번이나 재설치해보고 검색해서 들어왔습니다.. ㅎㅎ

    2011.03.22 19:47 신고 [ ADDR : EDIT/ DEL : REPLY ]
  3. 호잉

    아 이글 보고 해결했네요..
    이거때문에 하루를 삽질했는데.. 이방법 보고 해결되는거 보고 빵터졌습니다..

    2011.03.25 14:17 신고 [ ADDR : EDIT/ DEL : REPLY ]
  4. 낭만고양이님도 IT 쪽인 것을 잊고 있었네요. 저도 스마트폰 APP 관련된 일을 하고 있어서 더 반갑네요...

    2011.04.18 11:30 신고 [ ADDR : EDIT/ DEL : REPLY ]
  5. 요다

    치트키두 아니구..ㅎㅎ 감사합니다.

    2011.06.07 13:39 신고 [ ADDR : EDIT/ DEL : REPLY ]
  6. 궁금이

    허무해요..... ㅠㅠ

    2011.07.04 11:58 신고 [ ADDR : EDIT/ DEL : REPLY ]
  7. 봉팔이

    감사합니다... 한참 웃었네요..

    2011.07.11 12:43 신고 [ ADDR : EDIT/ DEL : REPLY ]
  8. 롸키

    감사합니다^^ 이글 보고 너무 쉽게 해결했네요ㅋㅋㅋ
    큰웃음 주셔서 감사합니다ㅋㅋㅋ

    2011.07.14 12:19 신고 [ ADDR : EDIT/ DEL : REPLY ]
  9. 와우 !

    검색해서 처음 본 글이 이거라 다행이에요 ! ㅋㅋㅋㅋ
    한참 고민할 뻔한걸 금방 해결했습니다 ~ 정말 감사해요 !
    근데 정말 웃겨요 ㅋㅋㅋㅋ

    2011.07.15 10:22 신고 [ ADDR : EDIT/ DEL : REPLY ]
  10. 와하하..

    진짜 이 문제 때문에 더운 여름밤에 땀 삐질삐질 흘리고 있었는데...
    완전 빵 터지며 시원~하게 해결됐습니다..ㅋㅋㅋㅋ
    감사합니다..

    2011.07.23 02:44 신고 [ ADDR : EDIT/ DEL : REPLY ]
  11. 굿`~

    당신은 능력자~~

    2011.08.02 00:10 신고 [ ADDR : EDIT/ DEL : REPLY ]
  12. 헐....

    이걸로 며칠을 삽질을 했는데....jdk, 이클립스 미친듯이 깔고 지우고를 몇번이나 했는데 말이에요....ㅠㅜ

    2011.08.23 22:52 신고 [ ADDR : EDIT/ DEL : REPLY ]
  13. 호호호

    정말 감사해요:) 이것땜에 완전 짜증났었는뎅

    2011.08.27 19:26 신고 [ ADDR : EDIT/ DEL : REPLY ]
  14. 이럴수가

    이럴수가..... JDK를 세번 재 설치 했는데..ㅋㅋ
    너무 확실한 해결책입니다 ㅎㅎ

    2011.09.06 11:11 신고 [ ADDR : EDIT/ DEL : REPLY ]
  15. 아아...

    감사합니다... 한번에 풀리네요 ㅠㅠ JDK만 몇번 재설치했는데..

    2011.09.10 07:42 신고 [ ADDR : EDIT/ DEL : REPLY ]

Languages/Objective-C2011.02.08 11:02
뷰에 그려지는 내용은, 사실 CALayer 객체 위에 그려집니다. 뷰에 대해서 animation을 적용할 수 있듯이, CALayer 객체에 대해서도 animation을 적용할 수 있습니다.

CALayer에 대한 reference를 찾아보시면 아시겠습니다만, CALayer 객체에는 여러 개의 애니메이션 가능한 프라퍼티들이 있습니다. CALayer는 key-value coding을 지원하기 때문에, 키 값을 사용해 이들 프라퍼티에 애니메이션을 지정할 수 있습니다. 

이런 애니메이션은 적용하기도 간단합니다. 물론 복잡한 애니메이션을 구현하려면 좀 심각한 코딩을 해야 하겠습니다만, 레이어 하나 위에 이미지를 그리고 그 이미지가 깜빡거리게 만드는 정도는 대단히 간단하게 처리할 수 있습니다. 아래의 코드를 보시죠.

UIImage* img = [UIImage imageNamed: @"testimg.png"];

CALayer* sub = [CALayer layer];

sub.contents = img.CGImage;

sub.frame = ...

[self.layer addSublayer:sub];

CABasicAnimation* ani = [CABasicAnimation animationWithKeyPath:@"opacity"];

ani.duration = 2.0;

ani.repeatCount = HUGE_VALF;

ani.autoreverses = YES;

ani.fromValue = [NSNumber numberWithFloat:0.0];

ani.toValue = [NSNumber numberWithFloat:1.0];

ani.timingFunction = [CAMediaTimingFunction functionWithName: kCAMediaTimingFunctionEaseInEaseOut];

[sub addAnimation:ani forKey:@"opacity"];


우선 새 레이어를 하나 만들구요. 그 위에 이미지를 얹습니다. 그런 다음 뷰의 backing layer 위에 해당 레이어를 얹습니다. 그런 다음 애니메이션 객체를 하나 만들어서 해당 애니메이션이 어떻게 실행될 지 지정한 다음에 해당 애니메이션을 새로 만든 레이어에 붙입니다.

유의해서 볼 부분은, 해당 에니메이션이 CALayer의 어떤 프라퍼티에 적용될 것인지를 적용하는 부분입니다. CALayer에는 opacity라는 프라퍼티가 있습니다. 이 프라퍼티는 레이어가 얼마나 투명한지를 결정하는 프라퍼티입니다. 위의 애니메이션은 그 지속 시간(duration)이 2초이며, 영원히(HUGE_VALF) 반복됩니다. opacity 값은 0.0에서 1.0으로 변했다가 다시 원래 상태로 돌아갑니다(autoreverse = YES). 

따라서 위에서 만들어 붙인 레이어에 그려진 이미지는 주기적으로 나타났다 사라지는 것 처럼 보이게 됩니다. 간단하죠?

레이어를 실제로 조작하는 것은 UIView를 가지고 프로그래밍하는 것에 비해 저수준(low-level) 연산처럼 보이기도 합니다만, 잘만 쓰면 뷰를 새로 만들지 않고도 프로그래밍할 수 있기 때문에, 성능 문제를 개선하는 데도 도움을 줄 수 있습니다.

신고
Posted by 이병준

TRACKBACK http://www.buggymind.com/trackback/303 관련글 쓰기

  1. 공중곡예사의 생각  삭제

    2011.02.08 11:28TRACKBACK FROM bjlee72's me2day

    [iPhone/iPad] CALayer에 대한 animation

소중한 의견, 감사합니다. ^^

  1. 나그네

    sub.contents = img.CGImage 부분에서 Cannpt convert CGImage to objc_object in argument passing 이 떠요 ㅠㅠ

    2011.04.22 20:54 신고 [ ADDR : EDIT/ DEL : REPLY ]
  2. 부따부따

    제가 깜박이는 애니메이션이 특정 버튼을 누르면 시작하고,

    이 버튼에 대한 프로세스가 끝나면 원래 상태로 돌아가는 것을 구현 하려고 하는데요

    실시간 영상을 처리하는 가운데 overlay에 대해 해당 애니메이션을 지정해줬는데

    좀처럼 쉽게되질 않네요 도움 주시면 감사하겠습니다.

    2011.07.15 17:36 신고 [ ADDR : EDIT/ DEL : REPLY ]