반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리

ColumnFixture Tutorial (Fitnesse)

2013. 8. 12. 10:38 | Posted by 솔웅


반응형

Fitnesse에 대해서 공부하려고 하는데 검색을 해 봐도 별로 맘에 드는 블로그를 못 찾겠네요. 그래서 Fitnesse 홈페이지에 있는 Tutorial을 한번 쪽 훑어 보겠습니다.

기초적인 Research는 된 것 같아서 Fixture에 대한 부분을 살펴 봅니다.

여기로 가시면 Tutorial 원문을 보실 수 있습니다.

ColumnFixture


ColumnFixture 는 table 의 컬럼들을 곧바로 fixture class의 프로퍼티와 메소드 그리고 필드들로 매핑합니다. 이는 같은 테스트가 다양한 입력 argument들에 대해 반복적으로 사용되어야 할 때 반복적으로 사용되는 변수들을 만들 때 아주 유용합니다.

Table Format


테이블의 첫번째 줄(row)는 테스트 클래스의 이름입니다. 두번째 row의 컬럼 이름들은 이 컬럼과 관계된 필드나 메소드를 가리킵니다. Output 값들은 반드시 필드나 메소드 이름 다음에 ? 나 ()를 를 붙여야 합니다. 그 이후의 row들은 input argument들과 기대되는 결과값(output arguments)들의 combination list들 입니다.

!|info.fitnesse.fixturegallery.ColumnFixtureTest|
|firstPart|secondPart|together?|totalLength?|
|Hello|World|Hello, World|10|
|Houston|We Have a Problem|Houston, We Have a Problem|24|

Fixture class


fixture 클래스는 fit.ColumnFixture를 extend 해야 합니다. 그리고 테이블의 두번째 줄과 매치되는 public field들과 메소드들을 선언합니다.




Java Source Code

package info.fitnesse.fixturegallery;

import fit.ColumnFixture;

public class ColumnFixtureTest extends ColumnFixture {
	public String firstPart;
	public String secondPart;
	private int length;
	public String together(){
		length=firstPart.length()+secondPart.length();
		return firstPart+ ", "+secondPart;
	}
	public int totalLength(){
		return length;
	}
}

.NET Source Code

using System;
using System.Collections.Generic;
using System.Text;

namespace info.fitnesse.fixturegallery
{
    public class ColumnFixtureTest: fit.ColumnFixture
    {
        public String firstPart;
        public String secondPart;
        public String Together
        {
            get
            {
                return firstPart + ", " + secondPart;
            }
        }
        public int TotalLength()
        {
            return firstPart.Length+secondPart.Length;
        }
    }
}

Python Source Code

from fit.ColumnFixture import ColumnFixture

class ColumnFixtureTest(ColumnFixture):
    _typeDict = {
        "firstPart":  "String",
        "secondPart": "String"
    }

    def __init__(self):
        ColumnFixture.__init__(self)
        self.firstPart  = ""
        self.secondPart = ""

    # JAVA: public String together(){
    _typeDict["together"] = "String"
    def together(self):
        return "%s, %s" % (self.firstPart, self.secondPart)

    # JAVA: public int totalLength(){
    _typeDict["totalLength"] = "Integer"
    def totalLength(self):
        return len(self.firstPart) + len(self.secondPart)


Notes


자바버전에서는 클래스 필드들은 오직 input으로 사용되고 클래스 메소드들은 output으로 사용될 수 있습니다. JavaBean 프로퍼티들은 직접적으로 support 되지는 않습니다. (getter들이 output method들의 역할을 할 겁니다. 여러분은 getCreditLimit와 같은 전체 메소드 이름을 명시해야 합니다. .NET 버전에서는 필드들과 프로퍼티들이 input과 output들로 사용될 수 있습니다. 게다가 파라미터가 없는 메소드들도 output으로 사용될 수 있습니다. Java implementation은 대소문자 구분을 합니다. (case sensitive) .NET 버전은 프로퍼티 이름들에 대소문자 구분을 무시합니다.

table row들은 top-down 으로 실행됩니다. cell들도 왼쪽에서 오른쪽으로 실행되구요. 만약 row들이 실행되는 사이에 어떤 특별한 cleanup을 해야 한다면  reset() 메소드를 override하시면 됩니다.

.NET 버전은 ColumnFixture 로 domain object들을 감쌉니다. 이렇게 하면 fixture내의 도메인 object들의 프로퍼티들과 메소드들을 재선언 하지 않고 ColumnFixture 를 사용할 수 있도록 해 줍니다. Target objects로 가시면 좀 더 자세한 내용을 보실 수 있습니다.

output cell 을 empty로 놔두면 아무것도 테스트 하지 않고 현재의 값이 표시 됩니다.

Usage

 
ColumnFixture 는 calculation-based business rule들과 state machine들에 대해 테스트를 만들 떄 적합합니다. 같은 타입의 calculation이 다른 input 값들을 받아서 결과를 테스트하는 작업을 할 때 아주 유용합니다.

만약 테스트가 반복적이지 않다면 ColumnFixture 를 사용하는 것이 아주 좋은 방법이 아닐 수 있습니다. DoFixture (see DoFixture )를 한번 고려해 보세요. 만약 object들의 다이나믹한 리스트를 테스트하시려면 ArrayFixture (see ArrayFixture) 나 RowFixture 를 사용하세요. 이 Fixture들은 contents들도 verify 하거든요.


사람들은 가끔 이 ColumnFixture 를 잘 못 사용하기도 합니다. 특히 domain object나 데이터베이스에 record들을 insert 할 때 말이죠. 이를 위해서는 테이블의 마지막 칼럼에서 Create 를 call 함으로서 추가적인 메소드를 실행시킵니다. 이 메소드는 OK 같은 status code를 return 합니다. 이것은 creation에 대한 비지니스 룰을 체크하기를 원할 때 사용하면 좋습니다. 다른 테스트들의 stage를 준비하기를 원하신다면 SetUpFixture (see SetUpFixture )를 사용하면 좋습니다. 이 Fixture는 test page를 좀 더 가독성 있도록 해 줍니다. 또한 코드량도 줄일 수 있습니다.


반응형


반응형

지난번에도 Mockito 를 다룬적이 있는데요.

그 때는 다른 블로그에 있는 Mockito 관련 글을 번역해서 공부해 봤습니다.

예제들도 Android 를 중심으로 만들었구요.

 

오늘은 제가 참여하고 있는 Spring Framework에서 jUnit 테스트를 Mockito 를 사용해서 만든 경험을 정리해 보겠습니다.

 

일반적으로 jUnit 테스트 만드는 방법을 웹에서 검색하면 아주 간단한 예제들이 나옵니다.

하지만 실제 프로젝트에서 jUnit 테스트를 만들다 보면 이게 그렇게 간단하지 않거든요.

 

테스트하는 메소드 내에서 다른 메소드를 호출해서 return 값을 받아서 그 다음 일을 진행하기도 하고 또 호출한 메소드 내에서 또 다른 메소드의 호출이 일어나기도 하고요.

 

이럴 경우 Mockito 를 사용하는데 이번에 제가 실제 프로젝트에 참여하면서 경험하고 배운 내용을 정리합니다.

 

Spring Framework에는 Controller - Service - Transaction 이렇게 세개의 Layer로 나눠집니다.

 

Controller 부분은 Client Web 부분과 소통하고 Transaction은 SOA 나 DB 랑 소통합니다.

 

 

 

제가 참여하는 프로젝트의 흐름을 간단히 설명 드리면 Client 웹 브라우저의 form 문을 통해서 Controller에 어떤 데이터가 전달 됩니다. (이 때 세션값들도 받구요.)

그럼 Controller에서는 이 데이터를 기반으로 Bean 을 만들어 Service Layer로 던집니다. 그러면 Service Layer에서는 DTO를 만들어 Transaction으로 패스하고 Transaction에서는 Request를 Web Service 로 보냅니다.

웹 서비스에서는 다른 시스템이나 디비와 소통하면서 Response를 받아 Transaction으로 던져 주고요. Transaction은 이 Response를 가지고 DTO를 만들어서 Service로 던져 줍니다.

그러면 이 Service에서는 이를 다시 Bean으로 만들어 Controller로 패스하구요.

Controller는 이 Bean을 가지고 ModelAndView를 만들어서 Client의 웹 브라우저로 전달해서 그 다음 서비스를 사용자에게 전달합니다.

 

대부분의 중요한 비지니스 로직은 다른 외부 시스템에서 많이 진행 되서 이 자바 콤포넌트 내에서는 크게 비지니스 로직이 있지는 않습니다.

 

여기서 Controller에 있는 한 Method에 대해 jUnit 테스트를 만들게 되면 이 메소드가 Service 의 메소드를 호출하고 이 서비스에서는 다시 Transaction을 호출하고 여기서 다시 웹서비스를 call 해서 거기서 어떤 응답을 받게 되는 모든 과정이 진행됩니다.

 

그래서 단순하게 Controller에 있는 한 Method를 테스트 하려면 이 Service 에 있는 Method를 Call 하는 부분에서 그 return 값을 Mock 하면 됩니다.

 

이를 위해 저는 Mockito를 사용합니다.

 

아래는 지금 주료 사용하는 Mockito의 주요 기능을 정리합니다.

 

@RunWith(MockitoJUnitRunner.class)

처음 Mockito를 사용한다고 선언하는 부분입니다.

프로젝트에서 사용하는 소스코드를 사용할 수 없어서 API 에 있는 예제를 가지고 설명하겠습니다.

 

@RunWith(MockitoJUnitRunner.class)
public class ExampleTest {

    @Mock
    private List list;

    @Test
    public void shouldDoSomething() {
        list.add(100);
    }
}

이 예제는 여기 에 있는 API 문서에 있는 예제입니다.

 

우선 클래스 이름 선언하는 부분 위에 @RunWith(MockitoJUnitRunner.class) 를 선언함으로서 이 클래스에서 Mockito를 사용할 것이라는 것을 알립니다.

 

@Mock

그 다음에 private List list: 위에 @Mock 이라고 돼 있는데요.

이 부분을 Mock 할 거라는 것을 알리는 겁니다.

 

 

@InjectMocks

이 Annotation을 설명하기 위해 다른 예제를 보여드리겠습니다.

이 예제는 여기로 가시면 보실 수 있습니다.

 

public class ArticleManagerTest extends SampleBaseTestCase {

    @Mock private ArticleCalculator calculator;
    @Mock(name = "database") private ArticleDatabase dbMock; // note the mock name attribute
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @InjectMocks private ArticleManager manager;

    @Test public void shouldDoSomething() {
        manager.initiateArticle();
        verify(database).addListener(any(ArticleListener.class));
    }
}

public class SampleBaseTestCase {

    @Before public void initMocks() {
        MockitoAnnotations.initMocks(this);
    }
}

 

이렇게 사용하는데요. Mock 한 데이터를 이 @injectMocks 가 선언된 변수에 값을 inject하겠다는 내용입니다.주로 테스트하는 그 메소드에 이 inject 구문을 사용합니다. Mock 한 데이터를 넣어야 하는 곳이 그 메소드일 테니까요.

 

 

다음은 when().then() 구문을 설명할 텐데요.

when(mockedList.get(0)).thenReturn("first");

 

이 코드는 mockedList.get(0) 이라는 부분이 오면 그 return 값으로 first라는 스트링을 넣으라고 하는 명령입니다.

이게 바로 Controller에서 Service Layer에 있는 메소드를 호출 했을 때 이 Service 에 있는 메소드를 실행하지 않고 그 return 값을 mock 할 때 사용하는 구문입니다.

 

제가 참여하는 프로젝트에서는 이런식으로 사용됩니다.

when(service.method(isA(bean.class)).thenReturn(Bean)

 

클래스 이름이나 메소드 이름 그리고 input, return 파라미터 값들은 임의로 정한겁니다.

이 구문을 해석하자면 service 클래스에 있는 method라는 메소드가 호출 되면, 이때 method의 input 값은 bean.class 일 경우 입니다. 하여간 이 method가 호출되면 Bean을 return 하라는 명령입니다.

이전에 Bean을 별도로 생성해서 데이터를 세팅해 놔야 합니다.

 

이상이 제가 참여하는 프로젝트에서 jUnit 테스트를 만들 때 주로 사용하는 Mockito 기능들입니다.

저 위에 예제에서 나왔던 spy()라는 것도 몇군데 사용했는데요. 많이 사용하지는 않았습니다.

 

이 외에 Mockito 명령문은 아니지만 주로 많이 사용했던게 ReflectionTestUtils.setField 인데요.

 

Controller나 Service Layer 등등에서 다른 Layer의 메소드가 아니라 같은 Layer의 utility 클래스나 validator 클래스의 메소드를 호출하는 경우가 많이 있습니다.

 

이 때 이것을 사용했는데요. 다른 클래스의 메소드를 Mock instance로 처리하는 명령어 입니다.

이 기능은 Mockito의 기능이 아니라 Spring Framework의 API 인것으로 알고 있습니다.

 

 

 

반응형


반응형

지난 번 글을 쓴지 3주나 지났군요. 자기가 쓴 코드도 며칠만 지나면 뭐가 뭔지 너무 오래 되서 이전에 어디까지 공부했는지도 잘 모르겠습니다.


지난번 글 대충 읽어 봤더니 chainFunctions() 함수를 분석하면 될 것 같습니다.


이 함수에 전달되는 파라미터를 보겠습니다.


function chainFunctions(exec,options,runParent,noanim)


exec,options,runParent,noanim 이렇게 4개의 파라미터들이 전달 됩니다.


이 함수를 call 하는 anim 함수에서 이 함수가 call 되는 부분을 보죠.


return chainFunctions(function () return transition.to(obj,options) end, options,runParent)


첫번째 exec 에 해당 되는 부분은 function () return transition.to(obj,options) end 라는 함수 입니다. 여기서 obj,option 은 지난 번 글에 서 다뤘죠.




obj는 흰공의 위치이고 options는 빨간점의 위치값입니다.

그러니까 chainFunction 의 첫번째 인자는 흰공이 options 에 설정된 위치까지 움직이는 겁니다.

두번째 파라미터는 뭘까요?  options입니다. 이 options는 빨간공의 위치이죠? 흰공이 빨간공으로 움직이면 그 다음은 그 빨간공 자리에 흰공이 있게 되니까 그 위치가 흰공의 위치값이 될 겁니다. 아마 그걸 다루려고 이 options 값을 전달하는 것 같습니다.

코드를 분석 해 보면 나오겠죠.

세번째 값인 runParent 는 뭘까요? anim() 함수에서도 runParent를 던져주긴 하는데 이제 main 함수에서 call 됐을 때는 전달받지 못한 겁니다.


그럼 뭘까요?



anim() 함수가 main 함수에서만 call 되는 건 아닙니다. chainFunction() 함수 안에서도 이 anim() 함수가 호출되는데요.


return anim(arg[1],arg[2],run) 라는 부분이 있습니다.


여기에 세번째 파라미터가 있죠?

이건 chinFunction() 내부를 분석하면 뭔지 알 수 있을 겁니다.


그리고 chainFunction() 에는 네번째 파라미터가 noanim 이라고 있는데 anim() 함수에서 호출 될 때는 이 값이 없습니다.

자세히 보니까 chainFunction() 함수 내에서 자기 자신인 chainFunction()을 호출하는 부분이 있습니다.


return chainFunctions(arg[1],{},run,true)


이 4번째 파라미터는 true 이군요.

이것도 chainFunctions() 함수 내부 로직을 분석하면 어떻게 사용되는지 알 수 있을 것 같습니다.


들어가기 전에 이 소스를 만든 개발자가 적어 놓은 주석부터 한번 보겠습니다.


각 파라미터 (parameters, arguments) 들에 대한 설명을 달아 줬네요.


-- args
-- exec - is the current function to execute. It is assumed to be a function that runs a Corona SDK transition

exec는 현재 실행되는 함수이다. 이 값은 Corona SDK transition이 실행되는 함수가 전해질 것이다.


-- options - options for the animation (see Corona SDK). These are assumed to be the same closed over by the exec call - chainFunctions relies on being able to manipulate them for "onComplete" and "whenDone" to work

options 는 animation을 위한 것이다. (Corona SDK)를 보세요. 이것들은 chainFunctions에서 exec에 의해 실행 된 다음에 onComplete과 whenDone 이 됐을 때 생성되게 되는 것들이 될 것이다.


--         # Additional feature: if options.delete==true the subject of the animation will be deleted (obj:removeSelf() called) when the animation completes

# 추가 기능들 : 만약 options.delete 가 true 이면 애니메이션이 완료 되면 그 애니메이션 되는 대상은 delete 될 것이다. (obj:removeSelf() 가 call 됨으로서).


-- runParent (optional) - run the previous function in the chain. It takes a single function as an argument. chainFunction creates this function itself

runParent(옵션)은 chain에 있는 이전 함수를 실행한다. argument로 single function을 갖는다. chainFunction 이 이 함수를 생성한다.


-- noanim (optional) - true if exec does not represent a function executing a Corona SDK transition. If true, the only valid call to the chain is "start"

noanim(옵션) - true. 만약 exec 가 Corona SDK 의 transition을 실행하지 않을 때 이 값은 true 가 될 것이다. 그러면 여기서 start 함수만 call 될 것이다.




이렇게 친절하게 주석을 달아 주었네요.


이 주석만 봐도 대충 이 함수의 로직이 이해가 됩니다.


main 함수에서 설정했던 빨간공의 위치들이 돌아가면서 options 가 되서 흰공이 이 빨간공 위치로 계속 이동할 것이고 더이상 빨간공의 위치가 없으면 noamin이 true 가 되서 start 함수가 호출되서 끝나는 거군요.


오늘은 여기까지 하구요.


다음 글에서 제대로 chainFunctions() 부분을 분석해 보도록 하겠습니다.



반응형

Fitnesse 사용법 간단 정리

2013. 8. 7. 12:42 | Posted by 솔웅


반응형

요즘 제가 참여하는 프로젝트에 적용하려고 Fitnesse 를 Research 하고 있습니다.


나중을 위해서 간단하게 정리해 두겠습니다.


저는 FitLibrary 에 대해 알아보려고 검색하다가 관련된 파일을 다운 받았습니다.

정확히 다운 받은 곳을 못 찾겠네요.


필요하신 분은 구글링해서 다운 받으시기 바랍니다.

제가 다운 받은 파일 이름은 FitLibrary-2.0.zip 입니다.


Fitnesse 실행은 아래와 같이 합니다.


java -jar fitnesse-standalone.jar -o -p 8980 -e 0

 


처음 압축을 풀면 FitLibrary-2.0\fitnesse 폴더 내에 fitnesse-standalone 를 복사해 넣고 runFitNesseDirectly.bat 라는 배치 파일을 아래와 같이 수정하신 후 그 배치 파일을 실행 시키시면 됩니다.


java -jar fitnesse-standalone.jar -o -p 8980 -e 0
pause


이렇게 하고 나면 아래와 같은 콘솔이 뜹니다.


 

이제 Fitnesse 가 실행 된 겁니다.

 

브라우저를 열고 localhost:8980 에 접속해 보세요.

 

 

 

이 화면은 제가 좀 편집을 한 화면 입니다.

 

하여간 여러분도 성공하셨다면 비슷한 화면을 보실 겁니다.

 

여기서 테스트 테이블을 만들고 Fixture 작성해보고 또 test 를 실행해 보고 하는 것은 관련 예제들이 구글에 많이 있으니 그 예제들을 참고하시면 됩니다.

 

제가 작업하는 환경은 Spring Frame work 인데요.

이 프로젝트의 클래스들을 테스트 하기 위한 세팅방법을 Research 했었습니다.

 

그 클래스를 테스트 하려면 우선 해당 클래스들이 있는 jar 파일의 경로를 Fitnesse의 테이블 만드는 곳에서 설정을 해야 합니다.

 

!path C:\pcs\Fitnesse\java; ....

이런식으로요.

 

저는 프로젝트 build 한 후 target 폴더에 있는 jar 파일들을 임의의 폴더로 복사하고 그곳에 있는 jar 파일들을 path 에 적어 넣었습니다.

 

그 다음에는 Fixture 클래스를 생성할 프로젝트를 만듭니다.

저는 이클립스에 만들었습니다.

 

여기서 위의복사해 넣은 jar들을 프로젝트에 추가 시켜서 관련 테스트 Fixture를 만듭니다.

 

그리고 FItness 웹에 들어와서 관련된 테스트 테이블을 만들면 됩니다.

 

 

 

 

 

제가 샘플로 만들어 본 테스트 입니다.

 

이걸 save 한 다음 test 를 돌려보면 아래와 같은 결과를 얻을 수 있습니다.

 

 

 

 

오늘은 제가 요즘 research 하고 있는 것들을 기억해 두려고 간단하게 정리해 봤습니다.

 

다음에 기회가 되면 좀 더 디테일하고 실전에서 활용되는 팁을 정리하도록 하겠습니다.

반응형


반응형

안녕하세요.


제가 가입해서 활동하고 있는 단체에서 이번에 강연회를 개최합니다.





'사람사는 세상 샌디에고'가 주최하는 첫번째 강연회

 

 

1. '세계경제는 저성장 시대로 진입하는가?' by 박영철 교수

(World Bank 근무경력의 국제경제학 교수) 

8/16 금요일 7:00~8:15pm 

 

2. '이민생활과 민족주의' by 장호준 목사

(민족지도자 장준하 선생의 3) 

8/16 금요일 8:15~9:30pm  

 

장소예수 마을 교회

10635-B Scripps Ranch Blvd.

San Diego, CA 92131 (전화858-586-9191) 

                                                                                                  

 

한국분이시면 누구나 환영하오며,

원하시는 분에 한하여 자유로이 기부해주시면 감사히 받겠습니다.

기타 문의danchung811@gmail.com


 


< 박영철 교수님 약력 >

 


2010-1990: 원광 대학교 경제학과 국제 경제학 교수

1989-1974: World Bank 근무, French-speaking West African Countries
 

( Cote d'Ivoire, Senegal, Gabon, Mali 등) 담당, Country Economist and Project Analyst

1980-1983: 한국 국제 경제 연구소(KIEI) 와 산업 연구원( KIET), 수석 연구 위원

1974-1964: Belgium , 루뱅대학, 경제학과( 학사+석사+ 박사 학위 수여)

1962-1964: 한국 일보 기자

1957- 1962: 외국어 대학 불문과 + 군 복무



강사분들도 훌륭하시고 주제도 아주 좋습니다.

샌디에고 근처에 사시는 분들 많은 참여 바랍니다.


혹시 주위분들 중에 샌디에고나 LA 에 아시는 분 계시면 홍보해 주세요.


반응형


반응형

남북정상회담 대화록이 국가 기록원에 없다고 판명 남으로서 대선때 김무성, 권영세가 정치 공작에 이용한 그 대화록은 국정원에서 나온 것이 분명해 졌습니다.

이제 국정원 댓글 공작 사건이 아닙니다.

새누리당의 관권동원 부정선거로 그 범위가 넓혀 졌습니다.


미국에서는 박근혜 탄핵이나 해임감이라는 분석까지 나오는데..

한국은 어떤가요?

==============================

If you think the NSA is bad …



Protesters shout slogans condemning South Korean National Intelligence Service involvement in the country's last presidential elections, during a demonstration outside the Seoul city hall.



Americans are apparently blasé about government eavesdropping.

In the days after former National Security Agency contractor Edward Snowden revealed that Washington spies extensively on its own citizens, polls found that about half of Americans have no problem with such snooping, as long as it protects them from terrorism.

But a scandal unfolding here in South Korea illustrates how such domestic snooping can easily harm a democracy.


미국인들은 정부가 도청하는 것에 대해 관심이 없는듯하다.

국가 안보국의 전직 요원인 에드워드 스노우든이 정부가 시민에 대한 정보를 대대적으로 염탐하고 있음을 폭로한 후 절반의 미국 국민은 테러리즘으로부터 자기네들을 보호해주기만 한다면 그러한 염탐이 별 문제가 되지 않는다고 생각한다고 여론조사가 밝혔다.

하지만 현재 대한민국에서 벌어지는 사건은 그런 염탐 행위가 얼마나 쉽게 민주주의를 해칠 수 있는지를 잘 보여준다.


(Read More: Microsoft Helped NSA Access Encrypted Messages: Report)


The imbroglio — which has sparked student protests and candlelight vigils around Seoul — actually consists of two episodes rolled into one.


서울에서 벌어지고 있는 학생들의 시위와 촛불 집회를 촉발시킨 이 난국은 실제로는 두 가지의 개별 사건이 함께 연계되어 있다.


The most recent scandal heated up when left-wing lawmakers accused the intelligence agency, the National Intelligence Service (NIS), of trying to protect its turf by leaking a sensitive and secret transcript in late June.


가장 최근에 있었던 사건은 진보측의 국회의원들이 국정원이 자기네의 세력권을 지키기 위한 노력으로 지난 6월 말, 민감한 기밀 문서를 누출시킨 것을 비방하면서 일어났다.


The document revealed details of a 2007 summit between North and South Korean leaders. In it, a now-deceased South Korean president, Roh Moo-hyun, discussed the possibility of redrawing the rival Koreas' sea border to help build peace.

At the other end of the table was enemy No. 1: former North Korean despot, Kim Jong Il.

The revelation had the potential to skewer Roh's party, now the opposition. For many South Koreans, the episode amounts to treason.


그 문서는 2007년 남북 간의 정상회담의 상세한 내용을 담고 있었다. 지금은 고인이 된, 당시의 대통령, 노무현 대한민국 대통령은 남북 간의 평화를 위해 남북 간의 해양 분기선을 조정할 가능성을 논의하였다.

정상회담의 상대방은 대한민국의 제일의 적인 북한의 전 독재자 김정일이었다.



(Read More: America's NSA 'In Bed With" Germany and Most Others: Snowden)


But the motive for the disclosure may have gone deeper.

Lawmakers claim that the spy agency was attempting to distract the public from yet another explosive affair: a clandestine NIS propaganda operation to influence the December 2012 presidential election.


그러나 그 폭로의 의도는 다른 곳에 있을 수도 있다.

국회의원들은 국정원이 지난 2012년 12월 대통령 선거에 영향을 주기 위해 비밀리에 선거 개입 작전을 벌였던 또 하나의 커다란 사건으로부터 대중의 관심을 돌리기 위해 이 문서를 폭로한 것이라고 주장한다.



In late 2012, two NIS agents published thousands of online comments in support of Park Geun-hye, the conservative politician who was elected president in December. The young spooks tried to smear the political left, claiming some were North Korean sympathizers and communist instigators.


2012년 말, 두명의 국정원 요원이 12월에 대통령으로 당선된 보수파 정치인, 박근혜를 지지하는 수천개에 달하는 인터넷 댓글들을 달았었다. 이들은 야당쪽 진보 정치인들이 종북주의자이고 공산주의 신봉가라고 몰아부쳤다.


In the raucous political system of South Korea, it's common for the mainstream press and pundits to paint their opponents in extreme ways.

The propaganda campaign didn't stay secret for long. Last month, the former spy chief, Won Sei-hoon, was indicted on allegations that he personally orchestrated the operation; the former Seoul police chief is also being prosecuted for supposedly whitewashing the first investigation into the case.


이렇게 극단적인 방법으로 상대방을 비방하는 것은 시끄러운 한국의 정치체제 아래에서 주요 언론과 전문가들마저도 종종 취하는 방법이다.

이 선거 선전 작전은 오랫동안 비밀로 유지되지는 못했다. 원세훈 전 국가정보원장은 지난 달 직접 이 작전을 지휘한 혐의로 결국 기소되었고, 이에 대한 초기 조사를 축소, 은폐하려 했던 혐의로 전 서울 경찰청장 또한 기소되었다.


(Read More: This Is Like the 'Cold War': Europe Fumes Over US Spying)


The NIS insists that it acted within legal bounds when declassifying the summit transcript. Under South Korean law, the head of the agency can request the release of state secrets if it does not pose a threat to national security.


국정원은 남북정상회담록을 공개한 것이 합법적인 범위 내에서 취한 행위라고 주장한다. 대한민국 법에 따르면, 국가정보원장은 국가의 안보가 위협되지 않는 한 국가 기밀 열람 공개를 요청할 수 있다.


It released the document out of concern for the "deepening schisms in the public" and its "negative effect national security," according to a statement issued on July 10.

An NIS spokesman could not be reached for comment.

Under South Korean law, documents of this sensitivity held by the National Intelligence Service would typically stay classified for up to 15 years. Two-thirds of lawmakers would have to agree, or a court order issued, before release into the presidential archive.


7월 10일에 국정원이 발표한 성명서에 의하면, "점점 악화되는 국론의 분열"과 "국가 안보에 대한 위협"을 우려하며 이 기밀 문서를 공개했다고 주장했다.

이에 대해 국정원 대변인으로부터 아무런 언급도 들을 수 없었다.

대한민국 법에 따르면, 국가정보원에 의해 보존되는 이런 예민한 문서는 통상적으로 최대 15년까지 기밀 문서로 분류된다. 대통령의 문서로 공개되기 위해서는 적어도 전체 국회의원의 3분의 2가 동의하거나, 법원의 명령이 있어야 한다.


Read more from the GlobalPost


FEMA hacked: Anonymous hacks US server in defense of Snowden and government transparency
Whistleblower Edward Snowden won't publish NSA 'instruction manual'
The NSA : America's ever-expanding digital spy agency


President Park, who prevailed with a 3 percent margin over her liberal opponent, insists that she didn't know of the plot and didn't reap any advantage.

Her administration points out that the NIS was meddling under the previous right-wing presidency of Lee Myung-bak, a factional rival and hardly a friend of Park's.

But given her family baggage, she's having a hard time maintaining distance.

In the 1960s and 1970s, her father, the dictator Park Chung-hee, used the precursor to the NIS for election rigging and other dark arts.


상대 후보보다 겨우 3% 차이로 당선된 박대통령은, 이와 관련하여 자기는 아는 바가 없으며 이로 인해 어떤 이득도 얻지 않았다고 주장한다.

박근혜 정부는 국정원의 대선개입은 당 내의 라이벌이자 결코 박근혜의 친구라고 할 수 없는, 우파 이명박 정권하에서 일어난 것임을 지적했다.

그러나 그녀의 가족사를 살펴본다면 박근혜는 이런 일에서 아주 거리가 멀다고 보기는 어렵다.

1960년, 70년대에 박근혜의 아버지인 독재자 박정희는 선거부정과 다른 불법적인 일들을 위해서 국정원의 전신인 중앙정보부를 이용했다.


The opposition is using the scandal to pin her to that legacy, say analysts. In Seoul, university students and activists have been protesting the revelations in recent weeks, calling for her removal.

According to polls, Park's popularity has slumped from more than half to about 40 percent in recent weeks. The Asan Institute, a Seoul-based think tank, says the decline is not necessarily a result of the spy scandal, but rather a return to "normal" levels after the election.


전문가들은 야당이 이런 선거 스켄들을 가지고 박근혜를 그 과거사에 연결시키려 하고 있다고 말한다. 서울의 대학생들과 운동가들은 최근 몇주 동안 국정원 선거개입에 대해서 시위를 하며 박근혜의 하야를 요구하고 있다.

여론조사에 의하면, 박근혜의 지지율은 최근 몇 주 동안 50% 이상에서 약 40% 정도로 급감하였다. 서울에 기반을 둔 씽크 탱크인 아산 연구소는 이런 감소가 꼭 국정원 스캔들의 결과가 아니고, 선거 이후 "정상치"로 돌아온 것이라고 설명한다.


(Read More: Hackers Shut Down Korean Sites on War Anniversary)



"She might be completely unscathed or, in the worst case, impeached and removed from office," said Daniel Pinkston, the Seoul-based senior analyst at the International Crisis Group, a nonprofit.


"박근혜는 피해를 전혀 입지 않을 수도 있지만 최악의 경우 탄핵 당하거나 대통령직에서 해임될 수 있다"라고 서울에 거주하고 있는 비영리 기구인 국제 위기 감시기구(ICG)의 선임 분석가 대니얼 핑크스톤은 말했다.


The NIS has long been prone to scandal. Out of the 11 heads who have served over the past decade, Won is the eighth to be investigated. 


국정원은 오랜 기간동안 스캔들에 연루되곤 했다. 지난 십여년 동안 국정원의 원장으로 일했던 11명의 국정원장 중 원세훈은 8번째로 수사의 대상이 된 사람이다.


Part of the problem, critics say, is that every president since 1988, the start of the democratic era, has sidelined the most talented officers in favor of political cronies. Under South Korean law, the NIS is required to stay neutral in domestic politics.

The result, they say, is a highly politicized (and some say bumbling) agency that gets into trouble every few years, and has failed to report key events such as Kim Jong Il's death in 2011.


비평가들에 의하면, 문제는 민주화 시대의 시작인 1988년 이후 모든 대통령이 가장 능력있는 인사를 그 자리에 앉히는 대신 자신의 측근을 선호한 데에 있었다고 한다. 한국의 법에 따르면, 국정원은 국내 정치에서 엄정 중립을 지키도록 요구된다.

그 결과 국정원은 대단히 정치색을 띄게 되고 (쓸모 없는 기관이라 표현되기도 하지만) 몇 년에 한 번씩은 문제에 휩싸이기도 했으며, 2011년 김정일의 사망같은 중요한 사건도 놓치는 등 본연의 임무를 다 하지 못하게 되었다.


Pinkston says the latest affair gives South Koreans an opportunity to fix the institutional flaws of the NIS, improving its intelligence-gathering abilities.

Call it a lesson for the US, where the National Security Agency, we now know, has nearly unchecked spying capacity. And while Americans apparently don't mind such a dragnet approach, South Korea shows how an unfettered spy network can go awry.


핑크스톤은 최근의 국정원 스캔들은 국정원의 제도적인 결함을 고치고 정보수집 능력을 향상 시킬 수 있는 기회를 한국 국민에게 가져다 준 것이라고 말한다.

이것은 국가 안보국의 첩보력을 거의 무사통과로 용인해준 미국을 위한 교훈이라 할 수 있겠다. 그리고 미국인들이 그런 첩보 방식에 관용적인 태도를 보이는 반면, 한국에서의 규제받지 않는 첩보망이 어떻게 잘못된 결과를 가져올 수 있는지를 보여준다고 할 수 있겠다


반응형


반응형

지난번에 이어 animation chain 소스를 분석해 보겠습니다.

지난번 글을 올린지 1주일이 지났나보네요.


지난번 main.lua 에서는 화면에 나오는 빨간 공 4개와 흰공 한개를 배치하는 로직이었습니다.

animationchain.lua 에서는 이 흰공을 4개의 빨간공을 따라서 움직이게 하는 코드가 있을 겁니다.


main.lua 의 마지막 줄에 이 작업을 하기 위해 animationchain.lua 에 있는 함수를 이렇게 call 했습니다.


animationchain.anim(c,stops[1]).whenDone(c,stops[2]).whenDone(c,stops[3]).whenStart(c,stops[4]).onComplete(c,stops[5]).onStart(function() print("done") end).start()


c 가 바로 흰공이었고 stops 에는 빨간공들의 위치값들이 있습니다.


animationchain.lua 의 소스는 아래와 같습니다.


local M={}
animationchain=M

local transition=transition
local setmetatable=setmetatable
local type=type
local error=error

setfenv(1,M)

local function start(anim,options,onStart,onComplete)
    return function()
        if options.delete then
            options.onComplete=function(obj)
                obj:removeSelf()
                if onComplete then
                    onComplete()
                end
            end
        else
            options.onComplete=onComplete
        end
        anim()
        if onStart then
            onStart()
        end
    end
end

-- args
-- exec - is the current function to execute. It is assumed to be a function that runs a Corona SDK transition
-- options - options for the animation (see Corona SDK). These are assumed to be the same closed over by the exec call - chainFunctions relies on being able to manipulate them for "onComplete" and "whenDone" to work
--         # Additional feature: if options.delete==true the subject of the animation will be deleted (obj:removeSelf() called) when the animation completes
-- runParent (optional) - run the previous function in the chain. It takes a single function as an argument. chainFunction creates this function itself
-- noanim (optional) - true if exec does not represent a function executing a Corona SDK transition. If true, the only valid call to the chain is "start"
function chainFunctions(exec,options,runParent,noanim)
    local t={}

    local mt={
        __index=function(t,k)
            local run=function(execChildAnim)
                local doIt
                -- wrap child animation in relation to previous call
                local onStart,onComplete
                if k=="onStart" or k=="whenStart" then
                    onStart=execChildAnim
                elseif k=="onComplete" or k=="whenDone" then
                    onComplete=execChildAnim
                end
               
                doIt=start(exec,options,onStart,onComplete)
               
                if runParent then
                    runParent(doIt)
                else
                    doIt()
                end
            end

            return function(...)
                if k=="start" then
                    return run()
                end
                if noanim then
                    error("animationchain: passing in pure functions must terminate the chain. Only call start after passing a single function into the chain")
                end
                if #arg==1 and type(arg[1])=="function" then
                    -- just a function has been passed in.
                    return chainFunctions(arg[1],{},run,true)
                end
                   
                return anim(arg[1],arg[2],run)
            end
        end
    }

    setmetatable(t,mt)
    return t

end

function anim(obj,options,runParent)
    return chainFunctions(function () return transition.to(obj,options) end, options,runParent)
end

return M


여기서 어느 부분이 제일 먼저 실행 될까요?


이 파일에는 크게 세개의 함수가 있습니다. 맨 처음에 start() 함수가 있구요. 두번째에 chainFunctions() 그리고 세번째로 anim() 함수가 있습니다.


start 함수가 맨 처음에 있고 이름도 start 이니까 이게 제일 먼저 실행 될까요?

아닙니다. 사실은 start() 함수는 이 세개중에 제일 나중에 실행 됩니다.


함수는 running time 중에 누군가가 call 해 주지 않으면 실행되지 않습니다.

마치 옛날 왕의 여자들처럼 나라를 run 하시는 왕이 call 하지 않으면 평생 독수공방해야 되듯이요.


제일 처음 실행되는 함수는 anim() 입니다. 왜냐하면 main.lua 의 맨 마지막 단계에서 이 함수를 call 했기 때문이죠.


이 anim() 함수는 무슨 행동을 할까요?


chainFunctions() 함수를 return 합니다. 즉 chainFunctions() 함수가 실행 되는 거죠.

여기서 파라미터로 function () return transition.to(obj,options) end 와 options, 그리고 runParent가 pass 됩니다.


이 파라미터들이 어디서 온건지 알아볼까요?




그냥 설명하면 길어질 것 같아서 위와 같이 정리해 봤습니다.

c 는 흰공이고 stops[1] 은 빨간공의 좌표 입니다.

빨간공은 따로 파라미터로 넘겨 주지 않습니다. 왜냐하면 흰공만 움직일 거니까요. chainFunctions() 에서 필요한건 빨간공의 좌표값뿐입니다.


우선 main.lua 에서 이 c(흰공) 과 stop[1] 첫번째 빨간공의 좌표를 넘겨 줍니다.

이걸 animationchain.lua 의 anim(obj,options,runParent) 함수가 받죠. 

여기서 obj 는 첫번째 파라미터로서 흰공 c를 말하고 options는 빨간공의 좌표 입니다. 그리고 세번째 좌표 runParent는 main.lua 에서 전달하지는 않았습니다.

이건 나중에 살펴 보겠습니다.


anim() 함수 안에서는 chainFunctions()를 콜하면서 3개의 파라미터를 전달하죠?

그런데 첫번째 파라미터는 함수를 전달해 줍니다.

transition.to(obj,options) 라는 함수 입니다.

transition.to()함수는 corona sdk 에서 제공되는 함수인데 애니메이션 표현할 때 아주 많이 사용합니다.

transition() 함수 API 를 보시려면 여기로 가셔서 참고하세요.


이 transition.to(obj.options)를 해석하자면 obj를 options 까지 움직인다는 의미 입니다. 즉 흰공을 stops[1] 까지 움직이는 거죠.


한번 소스 코드를 바꿔볼까요?


main.lua 에서

animationchain.anim(c,stops[1]).whenDone(c,stops[2]).whenDone(c,stops[3]).whenStart(c,stops[4]).onComplete(c,stops[5]).onStart(function() print("done") end).start()를 없애시고 animationchain.anim(c.stops[1])을 넣어 보세요.


그리고 animationchain.lau 의 anim() 함수 안에 

return chainFunctions(function () return transition.to(obj,options) end, options,runParent) 를 없애시고

transition.to(obj.options)를 넣어 보세요.


그러면 흰공이 가운데에서 왼쪽 빨간 점으로 움직일 겁니다.


main.lua 에서 animationchain.anim(c.stops[2]) 를 넣어 보세요. 

그러면 흰공이 곧바로 왼쪽 위에 있는 빨간공으로 움직이죠?


이렇게 해 보시면 transition.to() 함수의 기능을 확실히 아실 수 있을 겁니다.


일단 오늘은 animationchain.lua 파일에 있는 3가지 함수 중에 main.lua 에서 call 되서 가장 먼저 실행되는 anim(obj.options,runParent) 함수에 대해서 분석해 봤습니다.


이제 이 anim() 함수 안에서 chainFunctions()를 호출 하는 것을 확인 했습니다.

이때 3개의 파라미터가 전달 되는데 첫번째 파라미터는 흰공이 2번 빨간 공까지 transition 한다는 함수이고 두번째 파라미터는 options로서 이건 main.lua에서 부터 전달 된 빨간 공의 좌표 입니다.


runParent는 아직 정체를 알 수는 없습니다.


아마 이 소스의 핵심 부분인 chainFunctions()를 분석하면 알 수 있을 겁니다.


오늘은 여기까지만 하고요.


다음에 chainFunctions()를 분석해 보겠습니다.

반응형


반응형

Protesters Gather Locally in Response to Zimmerman Aquittal


Created: Sun, 14 Jul 2013 07:54:00 PST

Updated: Sun, 14 Jul 2013 08:02:13 PST





SAN DIEGO - Protesters planned to gather in City Heights and at Balboa Park Sunday night in response to George Zimmerman's acquittal in the shooting death of Florida teen Trayvon Martin last year.


지난해 플로리다에서 10대인 Trayvon Martin 을 총으로 쏴 사망하도록 한 죠지 짐머맨에 대한 무죄선고에 반대하는 시위자들은 일요일 밤 City Heights 와 Balboa Park 에 모이기로 했다.


The "San Diego Stand with Trayvon Martin Rally," began at 5:30 p.m. Highland Park was one of several events planned following the verdict that was announced Saturday.

At 7:30 p.m., "A Time for Healing Candle Vigil for Trayvon Martin" will be held at the Balboa Park fountain off Park Boulevard. The event is hosted by the San Diego NAACP and She is Soul.

오후 5시 30분에 시작된  "San Diego Stand with Trayvon Martin Rally," 는 토요일 발표된 배심원 평결문에 반발해서 계획된 여러 이벤트 중 하나였다. 오후 7시 30분에 "A Time for Healing Candle Vigil for Trayvon Martin"이 Balboa Park 분수대 밖인 Park Boulevard 에서 개최될 예정이다. 이 이벤트는 San Diego NAACP 와 She is Soul 이라는 단체에서 주최한다.



남미계 백인 경찰이 근무중 지시에 따르지 않는 흑인 소년에게 총을 쏴 죽게 만든 일이 작년 플로리다에서 일어났는데요.

지난 토요일 그 경찰이 무죄 평결을 받았습니다.

이에 반발하는 시위가 미국 여러곳에서 벌어지고 있습니다.


예전에 LA 폭동을 유발하는 로드니 킹 사건이 연상되네요.


이곳 샌디에고에서도 시위가 있었다고 하네요.


경찰 입장에서 보면 그 경찰이 이해가 가고 순진한 시민 입장에서 보면 그게 너무한 과잉 진압 인게 맞는 얘기고......


잘 모르겠네요.


한국도 국정원 선거개입에 항의하는 촛불집회가 점점 거세게 저항하고 있다죠?

모두 힘 내시고 이번일은 정말 상식적으로 처리되도록 했으면 좋겠습니다.


반응형


반응형

오늘은 정말 오랜만에 Corona SDK 의 한 샘플 코드를 받아서 공부 좀 해 봤습니다.


animationchain 이라는 소스인데요.


소스는 https://github.com/personalnadir/animation 에 가시면 보실 수 있습니다.


파일을 다운 받아서 실행시켜 보시면 아래와 같은 화면을 보실 겁니다.






화면에 빨간 점이 4개 찍혀 있고 하얀 공이 이 빨간 공들을 찍으면서 움직입니다.

궁금하신 분들은 파일 다운 받아서 직접 실행해 보시면 됩니다.


오늘은 우선  main.lua  파일을 분석해 보죠.


require "animationchain"

local stops={
    {x=20},
    {y=20},
    {x=200,simul=true},
    {y=600},
    {x=display.contentCenterX,y=display.contentCenterY,delete=true}
}

local x,y=display.contentCenterX,display.contentCenterY
for k,v in ipairs(stops) do
    x,y=(v.x or x), (v.y or y)
    if not v.simul then
        display.newCircle(x,y,10):setFillColor(255,0,0)
    end
end

local c=display.newCircle(display.contentCenterX,display.contentCenterY,20)
animationchain.anim(c,stops[1]).whenDone(c,stops[2]).whenDone(c,stops[3]).whenStart(c,stops[4]).onComplete(c,stops[5]).onStart(function() print("done") end).start()


첫번째 줄은 animationchain.lua 라는 파일에 있는 함수를 implement 한다는 얘기 입니다.

오늘은 main.lua 만 다룰거니까 이 animationchain.lua 파일은 신경쓰지 않겠습니다.


다음은 stops 라는 배열에 key,value 형식으로 값들을 집어 넣었습니다.


다음은 x 와 y라는 변수에 화면 중심의 x, y 값을 대입했습니다.


그 다음은 for 문으로 위에 정해 줬던 stops 라는 key,value 쌍으로 돼 있는 배열을 돌면서 원을 만드네요.

화면에 찍힌 4개의 빨간색 점들이 이 for 루프를 돌면서 찍힌 겁니다.


display.newCircle(x,y,10):setFillColor(255,0,0) 는 지름이 10픽셀인 원을 x,y 좌표에 그리는데 그 원의 색은 빨간색 (RGB 에서 R 만 255이기 때문에 빨간색이 됩니다) 으로 그리라는 뜻입니다.

그다음에 또 원을 그리네요 c 라는 변수에 담기는 원을 그리는데요.

20픽셀의 지름을 갖는 원을 그리는데 그 위치는 화면의 중앙이 됩니다.

따로 원의 색을 지정해 주지 않았기 때문에 디폴트인 흰색(255,255,255)이 됩니다.


그 다음은 아까 require 에서 지정한 animationchain 이라는 파일 안에 있는 anim() 이라는 함수를 call 하는 겁니다.


일단 이 부분은 오늘 다루지 않을 부분이구요.


for 문에서 main.lua 의 주요 작업이 다 진행되니 이 for 문을 집중적으로 보겠습니다.

처음에 나오는게 ipairs 함수 입니다.


이 함수는 3개의 값을 return 합니다.

신택스는

for i,v in ipairs(t) do body; end

입니다.


이럴경우 (1,t[1]), (2,t[2]), ..., 이런 값들을 리턴하는데요. 이 루프는 ipairs안에 있는 t 라는 테이블의 마지막에 있는 값까지 도달하면 끝이 납니다.



그럼 main에 있는 for 문을 볼까요?


for k,v in ipairs(stops) do
    x,y=(v.x or x), (v.y or y)
    if not v.simul then
        display.newCircle(x,y,10):setFillColor(255,0,0)
    end
end


for 문만 보면 stops 에 있는 값들의 갯수 만큼 for  문이 돌겠군요.

그리고 그 값들은 1,stops[1], 2,stops[2] 이런식으로 진행이 됩니다.


다음줄은 x 에 v.x 나 x 를 대입하고 y에는 v.y나 y 를 대입합니다.

그러니까 v.x 가 있으면 그 값을 대입하고 그 값이 없으면 위에 지정한 x 값 즉 화면 중앙의 x 좌표값을 대입하게 됩니다.


그러니 처음 x 값은 stops 의 첫번째 값인 20 이 대입될 겁니다. 그 다음엔 y 값은 없으니까 for 문 바로 위에 지정해 둔 화면 중앙의 y 값이 대입될 거구요.


그리고 그 값을 x,y 값으로 해서 지름 10짜리의 빨간색 원을 그릴겁니다.


그 다음은 다시 for 문 처음으로 가는데 x, 값은 아까 지정된 20이 있을 테고 그 다음은 stops[2] 가 선택이 되니까 y 값으로 20이 지정될 겁니다.


그 다음에 두번째 빨간색 원이 그려질텐데 그 위치는 20,20이 될 겁니다.


다음 for 루프 돌 때는 stops[3] 가 되서 x는 200 이 되겠구 y는 따로 없으니까 바로 전에 지정된 20이 되겠네요.


그런데 if 문에서 v.simul이 아닐 경우에만 원을 그리라고 했으니까 이 원은 그려지지 않을 겁니다.


말로 설명하면 잘 감이 안올 수도 있으니까 눈으로 확인해 보겠습니다.


local stops={
    {x=20},
    {y=20},
    {x=200,simul=true},
    {y=600},
    {x=display.contentCenterX,y=display.contentCenterY,delete=true}
}

local x,y=display.contentCenterX,display.contentCenterY
for k,v in ipairs(stops) do
    x,y=(v.x or x), (v.y or y)
    print (v.x )
    print (v.y)
    if not v.simul then
        display.newCircle(x,y,10):setFillColor(255,0,0)
        print (k ..  " : " .. x .. " , " .. y)
        cord = k .. " : " .. x .. "," .. y;
        display.newText(cord,x+10,y, native.systemFont, 20)
    end
end

local c=display.newCircle(display.contentCenterX,display.contentCenterY,20)


for 문 안에서 x, y 좌표를 console 하고 화면에 찍는 코드를 삽입했습니다.

그러면 결과는 아래와 같습니다.




보시면 첫번째 빨간 원은 20,427 이고 두번째는 20,20 입니다. 그리고 세번째는 200,20 이 될 텐데 if 문에 걸려서 이 세번째 원은 그려지지 않을 겁니다.

네번째는 200,600 이고 다섯번째는 stops 의 마지막 값으로 화면 정중앙에 있는 빨간 원이 그려집니다.



그냥 좌표값을 사용해서 그리면 될 텐데 왜 이렇게 복잡하게 할까요?


일단 이렇게 하면 코드의 양을 줄일 수 있고 빨간원이 그려지는 위치를 stops 배열 안에서 정해주면 되니까 나중에 수정하거나 할 떄 편해 집니다.

가독성이 좋고 maintanance 를 용이하게 해 주는 것이죠.


그리고 모바일은 기계마다 해상도가 다른데 이 stops 좌표를 각 해상도마다 따로 만들어 줘서 기계의 해상도에 따라서 다른 좌표를 사용해서 빨간 원을 그리게 할 때도 편리하게 이용할 수 있습니다.


맨 마지막 줄은 animationchain 파일에 있는 anim()함수를 call 하고 있습니다.

이 때 parameter들이 전달 되는데요.


첫번째 파라미터로 c 즉 하얀 원이 전달 됩니다. 이 c 가 움직일 거니까 이 객체를 파라미터로 전달해야겠죠.

그리고 두번째는 stops[1] 이 전달 됩니다. 이 하얀 공이 첫번째로 갈 목적지가 될 겁니다.


목적지에 도달하면 (whendone) 두번쨰로 c,stops[2] 를 인수로 해서 anim 을 call 하고 이 작업을 c,stops[5] 가 될 때까지 할 겁니다.


그 다음에 onStart()를 붙인 것은 transition이 일어나기 전에 이 onStart() 메소드를 실행하라는 의미입니다. 다음 파일안에 이 onStart 메소드가 있어야 되고 그 메소드 안에서 이벤트 대신 target이 pass 되도록 할 수 있습니다.


잘 이해가 안 되시는 분들은 API를 보시면 도움이 되실 겁니다.


여기서는 onComplete() 다음에 호출 되니까 공이 다 돌면 다음 transition 하기 전에 print 'done' 을 하라는 거네요.


그 다음은 animationchain 에 있는 start() 함수를 호출하는 거구요.


여기까지 main.lua 에 대해 공부해 봤습니다.


다음엔 이 오픈소스의 핵심인 animationchain 파일을 분석해 보겠습니다.


반응형


반응형
Posted on . Written by

 

Building on What’s There

 

이제 여러분의 함수가 API 에 있게 됐고 동작도 잘 되고 있습니다. 이제 코딩을 하면서 그 함수를 call 할 수 있는데요, API 의 새로운 기능을 알게 되는 건 기쁜 일이죠.

이제 기존에 string 라이브러리 함수들 중에 약간 문제 있는 것을 한번 살펴 볼까요. gsub() 함수는 개발자에게 쌈박한 기능을 제공하죠. documentation 페이지를 한번 보세요. 아마 이 함수는 기본적으로 search and replace 기능을 제공하는 함수라는 것을 아실 수 있으실 겁니다.

 

local str = "Hello banana"
print( string.gsub( str, "banana", "Corona user" ) )
--Outputs: Hello Corona user

 

이 함수의 한계는 key/value 를 테이블에 담아서 사용하게끔 기능을 제공하지는 않습니다. 아래처럼 말이죠.

local searchreplace = {
   Hello = "Success",
   banana = "Corona user"
}

 

이 기능을 가능하도록 하려면 테이블 내의 entry들에 대해 iterate 하기 위해 루프롤 돌려야 합니다. 그리고 각 entry 마다 gsub() 함수를 부르면 되죠.

local str = "Hello banana"
for k,v in pairs( searchreplace ) do
   str = string.gsub( str, k, v )
end

print( str )
--Outputs: Success Corona user

pairs() 함수는 searchreplace table에 있는 각각의 인덱스들을 identify 하고 그 이름과 값을 return 하는 함수입니다. Lua table 을 사전처럼 다룰 때 아주 유용하게 사용할 수 있겠죠. 루프 안의 내용들은 생각하지 마시고 이제 string replacement 를 어느곳에서나 사용할 수 있는 훌륭한 함수를 하나 만드신 것만 생각하세요.


이제 함수 안에 루프를 넣어 볼까요.

local function gsubEx( str, searchreplace )
   for k,v in pairs( searchreplace ) do
      str = string.gsub( str, k, v )
   end
   return str
end

이 함수는 string-replaceing 루프를 어느곳에서나 재사용할 수 있도록 해 줍니다.

gsubEx( str, searchreplace )
--Outputs: Success Corona user

아주 쉽죠?

 

Improving What’s There


이제 이것들을 다 같이 함치고 gsub() 함수에 override 해 보죠. 우선 gsub() 함수를 변수에 넣어야 합니다. 아까 보았듯이 Lua 에서는 아래와 같이 함수를 변수에 넣는 것을 지원해 주죠.

local gsub = string.gsub

이렇게 하면 이제 gsub 변수를 사용해서 gsub() 함수를 call 할 수 있게 된 거죠. 이제 함수를 저장했으니 우리가 만든 함수를 이 변수에 replace 해서 gsub 함수를 overwrite 하기만 하면 됩니다. 이 방법은 이미 다뤘었죠. 실제 gsub() 함수가 사용하는 같은 함수 파라미터들을 사용할 겁니다.

string.gsub = function( s, pattern, repl, n )
end


이 단 두 줄로 우리가 한 것은 gsub() 함수의 copy 를 가지게 된 것이구요 그리고 우리가 만든 함수로 이것을 replace 시킨 겁니다. 이제 여기에 마음대로 로직을 넣을 수 있습니다. 아래 로직으로 패턴 파라미터가 string 일 때와 table 일 때를 체크하게 됩니다.

if ( type(pattern) == "string" ) then
   --do something
else
   --do something else
end

string.gsub() documentation을 잠깐 보시면 이 패턴 파라미터가 항상 string 인 것만 보실 수 있을 겁니다.

패턴 파라미터가 string 이면 original 함수를 call 하면 됩니다.


if ( type( pattern ) == "string" ) then
   return gsub( s, pattern, repl, n )  --call the original function and return whatever it returns
else
   --do something else
end

패턴 파라미터가 string 이 아니면 즉 table 이라서 key/value 의 쌍을 이루는 값들이라면 아래와 같이 간단한 루프를 돌립니다. 이 루프는 else 구문 안에 만들어야 겠죠.

else
   --do something else (loop over the keys and replace them in the input string 's')
   for k,v in pairs( pattern ) do
      s = gsub( s, k, v )
   end
   return s
end

우리의 new parameter 이름과 패턴을 사용하기 위해 루프를 살짝 바꿔줬습니다.

 

 


Putting it Together

이제 이것들을 모두 다 합쳐 보죠. 우리가 override 한것과 new gsub() 함수는 아래와 같습니다.

local gsub = string.gsub
string.gsub = function( s, pattern, repl, n )

   if ( type(pattern) == "string" ) then
      return gsub( s, pattern, repl, n )
   else
      for k,v in pairs( pattern ) do
         s = string.gsub( s, k, v )
      end
      return s
   end
end

이 코드의 결과는 string.gsub() 함수가 우리가 만든 로직으로 replace 되게된 겁니다. 우리가 만든 로직은 파라미터가 일반적인 거면 original 함수를 call 하고 테이블이면 우리가 만든 로직을 사용하는 거죠. 짠! 이제 우리는 코로나에 우리만의 라이브러리를 추가했습니다.

print( string.gsub( "Hello banana", { Hello="Success", banana="Corona user" } )
--Outputs: Success Corona user

이렇게 하면 코로나에서 제공되는 어떤 API 라이브러리에도 여러분이 원하는 기능을 추가하실 수 있습니다.

 

Warning!

아마 이것 저것 하고 싶은 것들이 많이 떠오르시죠? 새로운 기능을 추가하실 때는 아래 내용들을 유념하세요.

 original 함수 변수에 저장하는 것을 잊지 마세요.
 함수 내에서 그 함수를 call 하지 마세요. 그러면 무한 루프에 빠지게 됩니다.
 여러분이 만든 함수 내에서 original 함수를 call 하는 조건을 반드시 넣어 주세요.

이건 약간 advanced topic 입니다. 그러니 여러번 직접 해 보시고 이 사용법이 익숙해 지도록 하세요. 직접 production-ready 코드에 넣어서 사용하는 것은 위험합니다. 충분히 테스트 하고 완전 숙지 한 다음에 사용하세요. 여기에는 많은 smoke 와 mirror들이 있습니다. 잘 못 하면 쉽게 좋은 기능을 잃어버릴 수 있습니다.

 


Examples

여기 여러분들이 흥미로워 하실 만한 유용한 내용들 몇개 소개해 드립니다.

1. “math” library — adding a function to calculate length:

--returns the distance between points a and b
math.lengthOf = function( a, b )
   local width, height = b.x-a.x, b.y-a.y
   return ( width*width + height*height ) ^ 0.5  --math.sqrt( width*width + height*height )
end

 

2. “math” library — adding a function to clamp values:

--returns a value clamped between a range
math.clamp = function( val, low, high )
   if ( val < low ) then return low end
   if ( val > high ) then return high end
   return val
end

 

3. print() function — overriding print() to not print when running on a device:

--override print() function to improve performance when running on device
if ( system.getInfo("environment") == "device" ) then
   print = function() end
end

 

4. “math” library — adding a function to calculate nearest multiples:

--rounds up to the nearest multiple
math.nearest = function( number, multiple )
   return math.round( (number / multiple) ) * multiple
end

 

References

    Variable number of arguments: http://www.lua.org/pil/5.2.html
    Lua closures: http://www.lua.org/pil/6.1.html
    First class values: http://www.lua.org/manual/5.2/manual.html
    Functions: http://www.lua.org/pil/6.html
    String trim() function: http://lua-users.org/wiki/StringTrim
    String recipes: http://lua-users.org/wiki/StringRecipes
    Author’s blog: http://springboardpillow.blogspot.co.uk/2012/04/sample-code.html 

반응형