Total: Today: Yesterday:
연구소/Google Docs | 2017. 10. 19. 12:33 | Posted by 자수씨

구글 스프레드 시트에서 스크립트 편집기를 통해 커스텀 함수를 만드는 법은 엑셀에서 VB스크립트와 방식이 유사하여 자주 사용하고 있었다.


이전에는 셀에 변경을 감지하여 작업을 처리하였는데 상단 메뉴바에 커스텀 메뉴를 추가하여 작업을 처리하는 방식을 공유하고자 한다.



스크립트 편집기에 접근하는 방식은 아래와 같다.


[상단 메뉴바] > [도구] > [스크립트 편집기...]



스크립트 편집기가 뜨면 기존에 있던 내용은 지우고 아래의 코드를 삽입한다.




### js


function onOpen() {

  

  var _spreadSheet = SpreadsheetApp.getActiveSpreadsheet();

  var _menuEntries = [];

  

  _menuEntries.push({

    name: "테스트",

    functionName: "test"

  });

  

  _spreadSheet.addMenu("UWO스터디", _menuEntries);

}


function test() {


Browser.msgBox("테스트");

}



Browser.msgBox 는 window.alert 의 개념이라고 보면 되며, 스크립트를 저장한 후 스프레드 시트를 새로고침하면 아래와 같이 커스텀 메뉴가 추가된 것을 확인할 수 있다.




실행하면 권한을 설정하는 부분이 있는데 설정 후에 다시 메뉴를 실행하면 메시지박스를 확인할 수 있다.



참고자료: https://developers.google.com/apps-script/reference/spreadsheet/spreadsheet#addMenu(String,Object)

연구소/TweenMax | 2017. 10. 18. 22:55 | Posted by 자수씨

HTML5 애니메이션 라이브러리로 TweenMax 를 사용할 경우 화면을 최소화 하거나 다른 탭에 의해 가려져 있으면 애니메이션이 동작하지 않는다.


그 이유는 기본적으로 TweenMax 애니메이션이 requestAnimationFrame 이벤트에 의해 동작하게 되는데, HTML5 의 특성인지 브라우저의 특성인지는 알 수 없지만 해당 이벤트가 발생하지 않기 때문이다.


따라서, 다음과 같이 설정을 해주어야 원하는 결과를 얻을 수 있다.


TweenMax.ticker.useRAF(false);


위의 useRAF() 함수는 requestAnimationFrame 의 사용여부를 설정하는 함수인데, 인자를 FALSE 로 넘길 경우 requestAnimationFrame 대신에 setTimeout() 함수를 통해 애니메이션이 처리된다.



관련사이트: https://greensock.com/docs/TweenMax/static.ticker

연구소/electron | 2016. 5. 16. 18:54 | Posted by 자수씨

스마트 개발자 협회 페이스북(https://www.facebook.com/sda.re.kr) 에 Electron 관련 글이 올라왔길래 어떤 용도로 활용이 가능한지 보기 위해서 기본 예제를 돌려보기로 했습니다.



Electron 홈페이지(http://electron.atom.io/) 에 접속하면 아래와 같은 화면이 나옵니다.


현재 주요 버전은 Electron 이 v1.0.1, Node 가 5.10.0 기반입니다.




이제 Electron Quick Start 를 해볼 차례입니다. (사전에 nodejs 와 git 이 설치되어 있어야 합니다.)


E:\Dev\nodejs> git clone https://github.com/electron/electron-quick-start


E:\Dev\nodejs> cd electron-quick-start


E:\Dev\nodejs\electron-quick-start> npm install


E:\Dev\nodejs\electron-quick-start> npm start


엥??? 실행했더니 다음과 같은 오류가 발생합니다.


> electron-quick-start@1.0.0 start E:\Dev\nodejs\electron-quick-start

> electron main.js



npm ERR! Windows_NT 6.1.7601

npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "start"

npm ERR! node v6.1.0

npm ERR! npm  v3.8.6

npm ERR! code ELIFECYCLE

npm ERR! electron-quick-start@1.0.0 start: `electron main.js`

npm ERR! Exit status 3221225781

npm ERR!

npm ERR! Failed at the electron-quick-start@1.0.0 start script 'electron main.js'.

npm ERR! Make sure you have the latest version of node.js and npm installed.

npm ERR! If you do, this is most likely a problem with the electron-quick-start package,

npm ERR! not with npm itself.

npm ERR! Tell the author that this fails on your system:

npm ERR!     electron main.js

npm ERR! You can get information on how to open an issue for this project with:

npm ERR!     npm bugs electron-quick-start

npm ERR! Or if that isn't available, you can get their info via:

npm ERR!     npm owner ls electron-quick-start

npm ERR! There is likely additional logging output above.


npm ERR! Please include the following file with any support request:

npm ERR!     E:\Dev\nodejs\electron-quick-start\npm-debug.log


구글링을 해보니 msvcp140.dll 과 같은 VC++ 14.0 (2015) 재배포 패키지에 포함된 파일이 없어서 발생된 문제였습니다.


VC++ 14.0 (2015) 재배포 패키지 설치 페이지(https://www.microsoft.com/ko-kr/download/details.aspx?id=48145) 에 접속하여 현재 OS 에 맞게 설치합니다.


다시 실행해보겠습니다.


E:\Dev\nodejs\electron-quick-start> npm start



크롬 기반의 웹 페이지가 GUI 어플리케이션 안에 들어가 있습니다.




최근에 nodejs 로 개발자 용 관리 페이지를 만들어볼까 했었는데, Electron 으로 시도를 해봐야겠습니다.





연구소/이것저것 | 2016. 4. 28. 14:11 | Posted by 자수씨


엑셀 시트로 저장된 데이터를 레드마인 위키에 옮길 때 주로 사용하던 컨버팅페이지가 있었는데, 단위가 큰 수를 적용하니 오류가 발생하였습니다.


방법을 궁리하다가 얼마전에 해보았던 Google Sheets Script editor 를 이용하여 포팅을 도전해보았습니다.



#h3 첫번째 시도



위와 같은 데이터가 있을 때 레드마인에서 테이블 형식으로 사용하기 위해서는 다음과 같은 문법으로 작성 되어야 합니다.


|_. 이름 |_. 출생년도 |_. 주급 | 

| 이정주 | 1983 | 500000 |
| 이은호 | 1986 | 480000 |
| 이수진 | 1989 | 450000 |
| 이혜원 | 1900 | 445000 | 


위와 같은 레드마인용 컨텐츠를 작성해주는 Google Sheets 용 script 를 작성해보았습니다.


### js


function toRedmine(input, hasTitle) {

  

  var _redmineContent = '';

  

  for (var i = 0; i < input.length; i++) {

    var _row = input[i];

    for (var j = 0; j < _row.length; j++) {

      var _col = _row[j];

      

      _redmineContent += '|';

      if (hasTitle == true && i == 0)

        _redmineContent += '_.';

      _redmineContent += ' ' + _col + ' ';

    }

    _redmineContent += '|\r\n'

  }

  

  return _redmineContent;

}


커스텀 함수를 사용하게되면 위와 같은 레드마인 문법으로 포팅된 것을 확인할 수 있습니다.


=toRedmine(A1:C5, true)



실제로 레드마인에 붙여보면 내용은 잘 나오지만 시트에서 본 형식이 아니라 만족스럽지는 않습니다.



포맷이 적용된 데이터를 보고싶은데 말이죠...




#h3 포맷팅된 값으로...


구글 시트의 문서를 찾아보니 range 를 이용하여 현재 화면에 보여지는 값을 가지고 올 수 있다고 합니다.

해당 함수를 이용하여 새로운 커스텀 함수를 만들어보았습니다.


### js


function toRedmine2(range, hasTitle) {

  

  var _redmineContent = '';

  var _values = SpreadsheetApp.getActiveSheet().getRange(range).getDisplayValues();

  

  for (var i = 0; i < _values.length; i++) {

    var _row = _values[i];

    for (var j = 0; j < _row.length; j++) {

      var _col = _row[j];

      

      _redmineContent += '|';

      if (hasTitle == true && i == 0)

        _redmineContent += '_.';

      _redmineContent += ' ' + _col + ' ';

    }

    _redmineContent += '|\r\n'

  }

  

  return _redmineContent;

}

새로만든 커스텀 함수는 기존과는 다르게 ```range```  를 문자열 형식으로 전달해야 합니다.


=toRedmine2("A1:C5", true)






처음에 설정했던 목표는 달성했으나 뭔가 정렬되지 않은게 아쉽습니다.




#h3 정렬을 해보자!!


구글 문서를 살펴보니 정렬된 데이터를 가지고 오는 함수가 있었습니다. ```range.getHorizontalAlignments()``` 해당 함수를 이용하여 레드마인의 정렬 문법을 적용시켜보았습니다.


### js


function toRedmine3(range, hasTitle) {

  

  var _redmineContent = '';

  var _range = SpreadsheetApp.getActiveSheet().getRange(range);

  var _values = _range.getDisplayValues();

  var _aligns = _range.getHorizontalAlignments();

  

  for (var i = 0; i < _values.length; i++) {

    var _row = _values[i];

    for (var j = 0; j < _row.length; j++) {

      var _col = _row[j];

      var _align = _aligns[i][j];

      

      _redmineContent += '|';

      if (hasTitle == true && i == 0)

        _redmineContent += '_.';

      else {

        if (_align.indexOf('right') > -1)

          _redmineContent += '>.';

        else if (_align.indexOf('left') > -1)

          _redmineContent += '<.';

        else if (_align.indexOf('center') > -1)

          _redmineContent += '=.';

      }

      _redmineContent += ' ' + _col + ' ';

    }

    _redmineContent += '|\r\n'

  }

  

  return _redmineContent;

}


세번째 커스텀 함수는 사용방법이 두번째와 동일합니다. 헤더 영역은 정렬이 먹지 않으므로 그 부분만 정렬되지 않도록 구성하였습니다.


=toRedmine3("A1:C5", true)






엑셀의 VBScript 는 문법이 손에 익지 않아 불편했는데 Google Sheets 는 주특기로 사용했던 자바스크립트로 개발이 가능하여 훨씬 빠르고 수월하게 원하는 기능을 만들 수 있었습니다.


앞으로도 자주 애용해야겠네요~




#h3 References

 - https://www.joecullin.com/data_converter/

 - https://developers.google.com/apps-script/reference/spreadsheet/range

 - http://webapps.stackexchange.com/questions/10629/how-to-pass-a-range-into-a-custom-function-in-google-spreadsheets

 - http://www.redmine.org/projects/redmine/wiki/RedmineTextFormattingTextile

연구소/AngularJS | 2016. 4. 20. 14:39 | Posted by 자수씨

AngularJS 서비스 상속에 대해 여러 글들을 읽어보고 현재 구성된 부분에 적용을 해보아도 생각했던 결과물이 나오지 않았습니다. 그래도 그 중 에서 가장 도움이 많이 되었던 글을 기반으로 서비스 상속 구조를 구현해보았습니다.




#h5 DaoBaseService.js

### js


"use strict";


myApp.factory('DaoBaseService', function($q) {

return function() {

var conn = null;

var client = new MySQL.Client();

client.setSocketImpl(new MySQL.ChromeSocket2());


this.setConnectionInfo = function(connectionInfo) {


conn = connectionInfo;

};


this.login = function() {


var deferred = $q.defer();

client.login(conn.hostname, parseInt(conn.port), conn.username, conn.password, false, function(initialHandshakeRequest, result) {


if (result.isSuccess()) {

deferred.resolve();

} else {

deferred.reject('Login error: ' + result.errorMessage);

}

}, function(errorCode) {


deferred.reject('Error returned from MySQL server: ' + errorCode);

}, function(result) {


deferred.reject('Cannot connect to MySQL server: ' + result);

});


return deferred.promise;

};


this.logout = function() {


client.logout(function(result) {

console.log('logout');

});

},


this.query = function(sql) {


var deferred = $q.defer();

client.query(sql, function(columnDefinitions, resultsetRows) {


deferred.resolve(resultsetRows);

}, function(result) {


deferred.reject('Never called: ' + result);

}, function(result) {


console.error('Server returned error: ' + JSON.stringify(result));

}, function(result) {


console.error('Cannot send query: ' + result);

});


return deferred.promise;

}

};

});


```DaoBaseService``` 는 클래스 형태로 factory 에 등록합니다. 이러한 형태로 만든 이유는 AngularJS 에서 제공해주는 ```$q``` 서비스를 사용할 때 별도로 파라미터로 넘기지 않고 factory 에 등록하면서 사용할 수 있도록 이런 방식으로 구성하였습니다.



#h5 UserDaoService.js

### js


"use strict";


myApp.service('UserDaoService', function(DaoBaseService) {


var daoService = new DaoBaseService;


daoService.findByUserIdx = function(userIdx) {


var sql = 'select * from tbl_user where useridx = ' + userIdx;

return this.query(sql);

};


return daoService;

});


#h5 TaskDaoService.js

### js


"use strict";


myApp.service('TaskDaoService', function(DaoBaseService) {


var daoService = new DaoBaseService;


daoService.findByUserIdx = function(userIdx) {


var sql = 'select * from tbl_task where useridx = ' + userIdx;

return this.query(sql);

};


return daoService;

});

각 DaoService 에서는 ```DaoBaseService``` 의 객체를 생성하고 해당 객체에 각 서비스에 특화된 함수를 정의합니다. 이 객체를 반환하면 해당 객체가 서비스로 등록됩니다.



컨트롤러에서 사용할 경우에는 기존에 서비스 사용하듯이 선언하고 사용하면 됩니다. AngularJS 에서 service 는 싱글턴으로 유지되기 때문에 이와 같은 방식으로도 상속개념을 사용할 수 있는 것 같습니다.


#h5 MainController.js

### js


"use strict";


myApp.controller('MainController', function($scope, UserDaoService, TaskDaoService) {


...

UserDaoService.login().then(function() {

return UserDaoService.findByUserIdx(userIdx);

}).then(function(resultsetRows) {

$scope.userInfo = resultsetRows;

}).catch(function(fault) {

console.error(String(fault));

}).finally(function() {

console.log('cleanup!!');

UserDaoService.logout();

});

...

});



이러한 방법으로도 가능한 것을 공유하기 위해 포스팅합니다~~



#h3 References

http://blog.revolunet.com/blog/2014/02/14/angularjs-services-inheritance/

http://stackoverflow.com/questions/26642174/angularjs-service-inheritance

http://blog.mgechev.com/2013/12/18/inheritance-services-controllers-in-angularjs/

http://mobicon.tistory.com/329

'연구소 > AngularJS' 카테고리의 다른 글

auth0 & firebase  (0) 2016.04.18
AngularJS 기본 개발 환경 구성하기  (0) 2016.04.14

연구소/이것저것 | 2016. 4. 18. 22:01 | Posted by 자수씨


최근에 나오는 라이브러리를 보면 ```"use strict"``` 라는 문구가 자주 보입니다.


strict 미국·영국 [strɪkt]

1. (규칙 등이) 엄격한

2. (사람이 남에 대해) 엄격한

3. (사람이 자신의 종교・신념 등에 대해) 엄격한


- 네이버 어학사전


사전에서 볼 수 있듯이 무언가 엄격하게 사용한다는 의미로 생각이 되는데, 간단하게 알아보려 합니다.



#h3 strict 모드의 정의


strict 모드로 설정하는 방법은 간단합니다. 코드 앞쪽에 ```"use strict"``` 를 추가하는 것 입니다.

### js


"use strict";

x = 3.14;       // This will cause an error (x is not defined)

위의 예제를 실행하면 콘솔 창에 아래와 같은 오류가 찍히게 됩니다.


Uncaught ReferenceError: x is not defined


정의가 되지 않은 x 로 인해 정상적으로 동작을 하지 않습니다.


### js


"use strict";

myFunction();


function myFunction() {

    y = 3.14;   // This will also cause an error (y is not defined)

}

위의 예제도 y 가 정의되지 않아 정상적으로 실행되지 않습니다.




### js


x = 3.14;       // This will not cause an error. 

myFunction();


function myFunction() {

   "use strict";

    y = 3.14;   // This will cause an error (y is not defined)

}

위의 예제는 x 가 사용되기 전에는 ```"use strict"``` 가 선언되지 않았으므로 y 에 대해서만 오류가 발생합니다.



#h3 왜 strict 모드를 사용하는가?


"보안" 자바스크립트를 작성하는 쉬운 방법이기 때문입니다. 다른 이유는 "올바르지 않은 문법" 을 사전에 검출할 수 있습니다.


strict 모드는 쓰기금지 프로퍼티의 정의, getter 전용 프로터피, 존재 하지 않는 프로퍼티, 존재하지 않는 변수, 존재하지 않는 객체에 대해 에러를 발생시킵니다.



#h3 strict 모드에서 허용되지 않는 문법


1. 정의되지 않은 변수의 사용

### js


"use strict";

x = 3.14;                // This will cause an error (x is not defined)

### js


"use strict";

x = {p1:10, p2:20};      // This will cause an error (x is not defined)


2. 변수나 객체의 삭제

### js


"use strict";

var x = 3.14;

delete x;                // This will cause an error


3. 함수 파라미터에 중복된 이름

### js


"use strict";

function x(p1, p1) {};   // This will cause an error


4. 8진수

### js


"use strict";

var x = 010;             // This will cause an error


5. 이스케이프 문자

### js


"use strict";

var x = \010;            // This will cause an error


6. 읽기전용 프로퍼티에 값 설정

### js


"use strict";

var obj = {};

Object.defineProperty(obj, "x", {value:0, writable:false});


obj.x = 3.14;            // This will cause an error


7. 조회 전용 프로퍼티에 값 설정

### js


"use strict";

var obj = {get x() {return 0} };


obj.x = 3.14;            // This will cause an error


8. ```eval```, ```arguments``` 문자열에 대한 변수로의 사용

### js


"use strict";

var eval = 3.14;         // This will cause an error

var arguments = 3.14;    // This will cause an error


9. ```with``` 사용

### js


"use strict";

with (Math){x = cos(2)}; // This will cause an error


10. ```eval()``` 에 정의된 변수 사용

### js


"use strict";

eval ("var x = 2");

alert (x);               // This will cause an error



#h3 References

http://www.w3schools.com/js/js_strict.asp

연구소/이것저것 | 2016. 4. 18. 15:12 | Posted by 자수씨

이전 포스팅에서는 너무 무지한 상태에서 쓰다보니 다시 봐도 이해가 안되는 듯 하여 쉬운 예제를 통해 정리해보겠습니다.


기존에 promise 패턴이 아닌 callback 방식의 경우에는 아래와 같이 코딩을 하였습니다.

### js


$.ajax({

  url: "/ServerResource.txt",

  success: successFunction,

  error: errorFunction

});


대부분 함수의 파라미터 객체에 function 을 설정하여 결과에 대한 처리를 했습니다. 이러한 경우 callback 이 중첩되어 소스의 가독성도 떨어질 뿐더러 관리가 안되는 단점이 있었습니다.



jQuery 1.5 버전 이후부터는 아래와 같이 ```done()```, ```fail()```, ```always()``` 를 이용하여 결과에 대한 처리를 지정합니다.

### js


var promise = $.ajax({

  url: "/ServerResource.txt"

});

  

promise.done(successFunction);

promise.fail(errorFunction);

promise.always(alwaysFunction);


```jQuery.ajax()``` 는 ```jQuery XMLhttpRequest(jqXHR)``` 을 반환하기 때문에 아래와 같은 방식으로도 구현이 가능합니다.

### js


$.ajax( "example.php" )    

    .done(function() { alert("success"); })    

    .fail(function() { alert("error"); })    

    .always(function() { alert("complete"); }); 


체인 방식이 아니더라도 jqXHR 객체에 직접 지정도 가능합니다.

### js


var jqxhr = $.ajax( "example.php" )    

    .done(function() { alert("success"); })    

    .fail(function() { alert("error"); })    

    .always(function() { alert("complete"); }); 

     

    // perform some work here ... 

     

    // Set another completion function for the request above

    jqxhr.always(function() { alert("another complete"); });



jQuery 1.8 버전 이후부터는 ```then()``` 함수를 사용하여 Promise 패턴을 적용할 수 있습니다.

```then()``` 의 첫번째 인자는 성공에 대한 액션, 두번째 인자에는 실패에 대한 액션을 지정할 수 있습니다.

### js


$.ajax({url: "/ServerResource.txt"}).then([successFunction1, successFunction2, successFunction3], 

                                          [errorFunction1, errorFunction2]);

 

//same as

 

var jqxhr = $.ajax({

  url: "/ServerResource.txt"

});

  

jqxhr.done(successFunction1);

jqxhr.done(successFunction2);

jqxhr.done(successFunction3);

jqxhr.fail(errorFunction1);

jqxhr.fail(errorFunction2);

### js


var promise = $.ajax({

  url: "/ServerResource.txt"

});

  

promise.then(successFunction, errorFunction);

### js


var promise = $.ajax({

  url: "/ServerResource.txt"

});

 

promise.then(successFunction); //no handler for the fail() event




Deferred 객체를 직접 만들어서 사용할 수 있는데, 그 방법은 아래와 같습니다.


### js


var timer;

$('#result').html('waiting…');

  

var promise = process();

promise.done(function() {

  $('#result').html('done.');

});

promise.progress(function() {

  $('#result').html($('#result').html() + '.');

});

 

function process() {

  var deferred = $.Deferred();

 

  timer = setInterval(function() {

    deferred.notify();

  }, 1000);

   

  setTimeout(function() {

     clearInterval(timer);

     deferred.resolve();

  }, 10000);

   

  return deferred.promise();

}




Promise 에 등록된 callback 들을 Deferred 가 각 상황에 맞게 호출해주는 방식입니다.


```then()``` 함수를 이용하면 아래와 같이 구현할 수 있습니다.

### js


var timer;

 

(function process() {

  $('#result').html('waiting…');

  var deferred = $.Deferred();

     

  timer = setInterval(function() {

    deferred.notify();

  }, 1000);

   

  setTimeout(function() {

     clearInterval(timer);

     deferred.resolve();

  }, 10000);

   

  return deferred.promise();

})().then(function() { $('#result').html('done.'); },

          null,

          function() { $('#result').html($('#result').html() + '.'); });



#h3 References

http://www.htmlgoodies.com/beyond/javascript/making-promises-with-jquery-deferred.html

https://api.jquery.com/category/deferred-object/




연구소/이것저것 | 2016. 4. 18. 14:05 | Posted by 자수씨

20대에는 신기술에 관심이 많아서 이것저것 많이 해보고 실무에 적용도 했었는데, 30대가 되고나니 업무도 많아지고 귀찮음 때문에 신기술에 대해 관심이 점점 떨어져갔습니다.


최근에 다시 신기술에 대해 공부하다보니 너무 많은 것들이 쏟아져 나와있었습니다. 그 중 하나가 promise 패턴인데, 항상 callback 가 진리라 생각하고 불편한 상황에서도 계속 쓰고만 있었습니다.



promise 패턴은 스펙 구현체들을 로드하여 사용할 수 있는데, 최근 가장 많이 쓴는 jQuery 에서도 promise 패턴을 활용할 수 있습니다.


jQuery 에서는 ```jQuery.when(deferreds)``` 로 제공이 되며 API 에 있는 예제를 하나씩 확인해보겠습니다.



아래 예제는 ```jQuery.when()``` 의 파라미터인 ```deferred``` 가 정상적으로 처리되면 ```deferred.then``` 에서 콜백과 같은 처리를 합니다. 기존의 방식과는 달리 콜백이 중첩되지 않는 구조입니다.


### js


$.when( $.ajax( "test.aspx" ) ).then(function( data, textStatus, jqXHR ) {

  alert( jqXHR.status ); // Alerts 200

});



```jQuery.when()``` 의 파라미터가 Deferred 나 Promise 가 아닐 경우에는 done 콜백이 즉시 실행됩니다.

### js


$.when( { testing: 123 } ).done(function( x ) {

  alert( x.testing ); // Alerts "123"

});


파라미터가 없는 경우에도 즉시 실행됩니다.

### js


$.when().then(function( x ) {

  alert( "I fired immediately" );

});




아래는 ```jQuery.Deferred()``` 를 이용한 예제인데, 아직 잘 이해가 되지 않는 부분이 있습니다. Deferred 객체에 대해 학습 후에 다시 정리해야겠습니다.

### js


var d1 = $.Deferred();

var d2 = $.Deferred();

 

$.when( d1, d2 ).done(function ( v1, v2 ) {

    console.log( v1 ); // "Fish"

    console.log( v2 ); // "Pizza"

});

 

d1.resolve( "Fish" );

d2.resolve( "Pizza" );


### js


var d1 = $.Deferred();

var d2 = $.Deferred();

var d3 = $.Deferred();

 

$.when( d1, d2, d3 ).done(function ( v1, v2, v3 ) {

    console.log( v1 ); // v1 is undefined

    console.log( v2 ); // v2 is "abc"

    console.log( v3 ); // v3 is an array [ 1, 2, 3, 4, 5 ]

});

 

d1.resolve();

d2.resolve( "abc" );

d3.resolve( 1, 2, 3, 4, 5 );




#h3 References

https://api.jquery.com/jquery.when/

https://api.jquery.com/category/deferred-object/

연구소/AngularJS | 2016. 4. 18. 00:24 | Posted by 자수씨

새로운 라이브러리나 프레임워크를 공부할 때는 manning 사의 in Action 시리즈를 자주보게 되는데, 이번에도 AngularJS 공부하기 위해 "AngularJS in Action" 을 살펴보고 있는 중입니다.


쭉 살펴보는 도중 외부 서비스를 사용하는 부분이 있었는데, auth0 와 firebase 입니다.



#h3 auth0


이름에서 볼 수 있듯이 auth0 는 인증과 관련된 서비스를 제공해줍니다. 


홈페이지: https://auth0.com




You can easily and quickly connect your apps, choose identity providers, add users, set up rules, customize your login page and access analytics from your Auth0 dashboard. It really is identity made simple for developers.


https://auth0.com/how-it-works - Overview


위의 내용을 간략하게 보면 내가 만든 애플리케이션에서 접속, 인증 프로바이더 선택, 유저 추가 등을 쉽고 빠르게 적용할 수 있게 도와주는 서비스입니다. 애플리케이션에 가장 기본이 되는 사용자 관련 처리에 대해서 고민거리를 줄여줄 수 있는 서비스라 생각됩니다.


최대 액티브 유저 기준 7,000 명까지는 무료이므로 간단한 시스템 만들 때는 활용하는 것도 좋아보입니다.




#h3 Firebase


이름과 아이콘을 봤을 때는 저장소를 제공해주는 서비스로 생각되었습니다.


홈페이지: https://www.firebase.com





Firebase can power your app's backend, including data storage, user authentication, static hosting, and more. Focus on creating extraordinary user experiences. We'll take care of the rest.

- firebase overview


Firebase 는 데이터 저장소, 사용자 인증, 호스팅 등 백엔드 서비스를 주로 제공합니다. 무료 사용자도 1GB 의 저장소를 제공하기 때문에 auth0 과 마찬가지로 장난감 만들 때 요긴하게 사용할 수 있을 것 같습니다.





나름 10여년 개발하면서 장난감을 만들곤 했었는데, 그 때마다 반복적인 작업 & 설정에 귀찮음을 느끼고 그만둔 것들이 많았습니다. 이런 서비스를 활용한다면 손쉽게 장난감을 만들 수 있을 것이라는 알 수 없는 자신감이 넘쳐 흐름을 느낍니다.




'연구소 > AngularJS' 카테고리의 다른 글

AngularJS 서비스 상속에 대한 고찰  (0) 2016.04.20
AngularJS 기본 개발 환경 구성하기  (0) 2016.04.14

연구소/node.js | 2016. 4. 15. 18:47 | Posted by 자수씨

회사에서 게임 개발/운영 업무를 하다보니 신규 컨텐츠 제작 시 반복적인 신규 리소스 배포작업을 하고 있었습니다.


node.js 공부도 할겸 배포 스크립트 만들어봤습니다.



#h3 배포하기


목표로 했었던 배포 환경을 포스팅용으로 구성해보았습니다.


  • source: 복사할 소스 이미지들이 있는 디렉토리
  • destination/project: 프로젝트(코딩)에 리소스 디렉토리
  • destination/share: 공유 디렉토리


PS E:\temp\sources\resources> tree /a /f

E:.

+---destination

|   +---project

|   |   +---A

|   |   +---B

|   |   \---C

|   \---share

|       +---1

|       +---2

|       \---3

\---source

        02.png

        03.png

        04.png



```Gruntfile.js```
### js

'use strict';

module.exports = function(grunt) {
var readline = require('readline');
var path = require('path');
var sourceDir = 'E:/temp/sources/resources/source';
var shareDestDir = {
root: 'E:/temp/sources/resources/destination/share',
bg: '1',
logo: '2',
icon: '3'
};
var projectDestDir = {
root: 'E:/temp/sources/resources/destination/project',
bg: 'A',
logo: 'B',
icon: 'C'
};
var resourceId = -1;

// Project configuration.
grunt.initConfig({
deploy: {
main: {
files: [
{cwd: sourceDir, src: ['02.png'], dest: [shareDestDir, projectDestDir], type: 'bg'},
{cwd: sourceDir, src: ['03.png'], dest: [shareDestDir, projectDestDir], type: 'logo'},
{cwd: sourceDir, src: ['04.png'], dest: [shareDestDir, projectDestDir], type: 'icon'},
]
}
}
});

grunt.registerTask('question', function() {
var done = this.async();
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.question('Input resource ID: ', function(answer) {
rl.close();
resourceId = answer;
grunt.log.writeln('입력받은 아이디: ' + resourceId);
done();
});
});

grunt.registerMultiTask('deploy', function() {

var options = this.options({
encoding: grunt.file.defaultEncoding,
timestamp: false,
mode: false
});

var copyOptions = {
encoding: options.encoding,
process: options.process,
noProcess: options.noProcess
};

this.files.forEach(function(filePair) {
var type = filePair.type;
filePair.src.forEach(function(src) {
var srcPath = path.join(filePair.cwd, src);
var destFileName = type + '_' + resourceId + '.png';
filePair.dest.forEach(function(dest) {
if (dest[type]) {
var destDirName = path.join(dest.root, dest[type]);
var destPath = path.join(destDirName, destFileName);
grunt.file.copy(srcPath, destPath, copyOptions);
grunt.log.writeln('Copy to ' + destPath);
}
});
});
});
});
grunt.registerTask('default', [
'question', 'deploy'
]);
};


기존에 ```copy``` 태스크를 ```deploy``` 로 변경하였으며, 하드코딩으로 파일 복사가 아닌 ```grunt.initConfig({...})``` 에 설정을 읽어들여 파일을 복사하도록 수정하였습니다.



빌드 스크립트 실행결과는 다음과 같습니다.


PS E:\temp\sources\grunt> grunt

Running "question" task

Input resource ID: 0001

입력받은 아이디: 0001


Running "deploy:main" (deploy) task

Copy to E:\temp\sources\resources\destination\share\1\bg_0001.png

Copy to E:\temp\sources\resources\destination\project\A\bg_0001.png

Copy to E:\temp\sources\resources\destination\share\2\logo_0001.png

Copy to E:\temp\sources\resources\destination\project\B\logo_0001.png

Copy to E:\temp\sources\resources\destination\share\3\icon_0001.png

Copy to E:\temp\sources\resources\destination\project\C\icon_0001.png


Done, without errors.



파일들이 복사된 경로를 트리형태로 보면 아래와 같습니다.


PS E:\temp\sources\resources> tree /a /f

E:.

+---destination

|   +---project

|   |   +---A

|   |   |       bg_0001.png

|   |   |

|   |   +---B

|   |   |       logo_0001.png

|   |   |

|   |   \---C

|   |           icon_0001.png

|   |

|   \---share

|       +---1

|       |       bg_0001.png

|       |

|       +---2

|       |       logo_0001.png

|       |

|       \---3

|               icon_0001.png

|

\---source

        02.png

        03.png

        04.png



지금까지 21번이나 복사하는 작업을 반복했는데, 왜 이런걸 만들 생각을 그동안 못했는지 눙물이 납니다 ㅠㅠ