블로그 이미지
윤영식
Full Stacker, Application Architecter, KnowHow Dispenser and Bike Rider

Publication

Category

Recent Post

전산이나 컴퓨터 용어를 그때 그때 찾아 보지만 정리를 하지 않고 있다. 그냥 잡학 사전처럼 나만의 용어 정리를 해보고 싶다.



Syntactic sugar

  

  - 위키피디아

    + 사람이 이해하고 쉽고 표현하기 쉽게 컴퓨터 언어를 디자인해 놓은 문맥이다. 

    + 사람이 사용하기 달콤하다는 것에 유래되었고 이들은 깔끔하고 명확하게 표현가능하다는 특징을 지닌다. 

    예로 Array를 든다.

get_array(Array, vector(i, j)) 로 표현하는 대신 Array[i,j] 와 같이 표현한다. 또는 

set_array(Array, vector(i,j), value) 를 Array[i,j] = value로 표현한다. 


  - 프로그래밍으로의 신택티 슈거

    + JSON can be considered SyntacticSugar for XML.

All languages are eventually translated to machine code, and therefore all language constructs could be termed (extremely useful) "sugar" around the operations of the machine.


  - 구글러 오스마니가 표현한 글을 보고 궁금해서 찾아봄 

Preview of ES6 Classes in Chrome. Syntactical sugar over today’s objects and prototypes. Cleaner syntax:


Traceur and 6to5 support minimal ES6 classes, https://6to5.github.io/features.html#classes-1 & https://github.com/esnext/es6-class compiles them down to ES5 too


궁금한건 빨리 정리하고 가자. 

'Computer Engineering > Want to Know Terms' 카테고리의 다른 글

[Terms] Test Double - Mock, Fake  (0) 2015.01.02
posted by 윤영식
2014. 12. 31. 19:31 Languages/Python

Dart는 점점 복잡해 지는 웹 애플리케이션을 좀 더 견고하고 확장 가능토록 만들기 위해 나온 언어이다. 구글의 수많은 웹 서비스를 생각해보면 자바스크립트가 아니라 좀 더 낳은 개발 언어로 웹을 개발하고 싶어할 것이고 그러한 요구에 자체적으로 Dart를 개발하고 퍼트리는 느낌이랄까. 마치 서버에서 Go를 만들어 자신들의 서비스에 광범위하게 쓰고 있는 것과 같은 이치일것 같다. 그래서 적어도 현업에서 사용하지않는다 해도 어떤 모습이 미래의 웹 개발 언어가 되어야 하는지 살펴볼 필요는 있겠다. 생각은 이렇다. 웹 프론트앤드 개발은 Dart를 서버 백앤드 개발은 Go를 구글은 실험하고 있는 단계이다. 이들 모두 3년이상 지속해서 소개되고 사용되고 구글 클라우드에 적용되고 있다. 그러나 Dart는 프론트 백앤드를 모두 개발할 수 있다. 우선은 프론트앤드에 집중해서 보도록 한다. 






Dart 개념 익히기 

  

  - Dart 언어 개발자인 길라드 브라차로 부터 다트에 대해 들어보자

    + Dart type checking system에 대해 설명하고 있다. 

    + 자바의 JVM 스팩을 쓴 개발자 답게 언어 전문가의 냄새가 물신난다.

   

  - Dart 언어 개발자의 전체 소개 동영상이다. 

    + 다트 플랫폼 전체를 간략히 잘 설명해 주고 있다. 꼭 보자 

   


  - Dart언어의 특징을 간략히 보도록 하자. (한글)

   - 처음은 무조건 사이트부터 방법해서 https://angulardart.org/ 

    + 다트 소개 영상이다. 모든 것이 잘 요약되어 있다. (시리즈 동영상들)

    + Angular의 철학에 근거해서 만들어 졌기 때문에 테스트 가능하고 간결한 웹개발을 이끈다.

    + Dart 언어를 사용하기 때문에 class, annotation, inheritance등은 자바 개발자에게 익숙함을 제공하고 확장가능한 웹을 만듦

    + 모던 웹을 위한 Shadow DOM, Web Component를 시작할 수 있다. 

    참조)  테스트 가능성은 Angular의 DI (Dependency Injection)을 통해 가능해 진다. 

             Two-way data binding을 통해 간결한 코드 개발이 가능하다.

    


  - Dart로 시작하는 AngularDart는 Web Component 스팩을 구현하고 있는 Polymer.dart와 함께 어떤 방향으로 가는지 먼저 본다. 

    + 본영상이 JavaZone에서 발표됐다는 것은 자바 개발자에게 아주 익숙한 신택스로 Dart 언어가 구성되었기 때문일 것이다. 

    


  - Dart 언어에 대해 개념을 잡자

    + https://www.dartlang.org

  - DartEditor를 사용한다. 

    + 이클립스 기반이어서 자바개발자에게 친근감 마저 든다. 

    + 패키지 import 와 이클립스 debugging 등 확장자가 .java 에서 .dart로 바뀌고 웹과 서버 모두를 개발 할 수 있다. 

    


  - 문법 요약은 Dart Tip 11개에 대한 동영상을 보자





Dart 익히기 


 - Dart를 가지고 웹을 개발할 때는 어떻게 하는지 보자 

    

  

  - 웹 애플리케이션을 개발과정을 읽어보자 다트로 어떻게 하는 거지?

    + 다트는 기본적으로 Dart VM 에서 돌어간다. 웹에서 작동하려면 두가지 방법이 있다. 

    + 첫째는 Chormium 브라우져에 Dart VM을 넣은 Dartium 브라우져에서 수행. 

       개발시 Dartium으로 수행하면 DartEditor(Eclipse기반)에서 바로 디버깅이 가능하다. 

    + 둘째는 dart2js 툴 또는 pub build를 이용해서 자바스크립트로 바꿔서 일반브라우져에서 사용하는 것이다.  

    + DartEditor에서 Tools --> Pub Build(integrated JS)를 선택하면 모던 브라우져 모두에 수행 가능한 파일이 생성된다.

       


  - 본격적으로 Dart 강좌를 들어가자

  - Dart의 유용한 글과 라이브러리는 다토스피어(http://www.dartosphere.org/) 에서 검색한다. 

    + 다크관련 블로그 글들

    + 라이브러리 업데이트 현황

    + https://pub.dartlang.org 에서 배포된 다트 라이브러리를 찾을 수 있다.




Dart 는 메이져 모던 브라우져에서 수행된다. 


  - Dart를 Javascript로 변환해 주는 과정에 대한 설명 

    + 자바스크립트로 변환하고 top level 펑션은 $.main 이다. 

    + Tree Shaking 통해 필요없는 코드를 떨구어내고 자바스크립트로 전환한다는 의미 

    + Dart의 특징을 자바스크립트 코드로 어떻게 이식하고 있는지 설명한다. 예) Class 상속

    + JS로 전환할 때 많은 알고리즘과 방법이 동원되고 있다. 역시 문제 해결을 위해 알고리즘이 중요함 

    + JS로 전환할 때 --minify 로 사이즈를 줄여서 얻을 수 있다.(45분) 

    + 손으로 작성한 JS보다 성능이 좋다. 결론은 이것이다. 모바일에서 더 낳은 성능을 얻고 싶다면!!!

     

     



  계속해서 업데이트 예정...




<참조> 

  

  - dartlang.org




'Languages > Python' 카테고리의 다른 글

[AngularDart] 앵귤러다트 배우는 방법  (0) 2014.12.24
[Dart] 다트 언어 개념잡기  (0) 2014.12.24
posted by 윤영식
2014. 12. 27. 16:58 Angular/Prototyping

Web Components(웹 컴포넌트)는 W3C에서 나왔다. 웹 도큐먼트의 표현을 위젯이나 컴포넌트로 빌딩하는 개념으로 핵심은 HTML 앨리먼트끼리 상호작용하고 인캡슐레이션되게 만드는 기술이다. 2013년2014년 Google I/O 에서 Web Components에 대해 바이들맨이 설명을 상세히 하고 있다. 또한 Web Components org 사이트가 존재하여 관련 정보를 얻을 수있다. 







Web Components 구성 요소 


    


  - Shadow DOM

    + DOM과 Style을 인캡슐레이션 해준다. 

    + 예전에는 iframe등을 통해 위의 효과를 얻었다. 

    + shadow dom 외부의 js는 접근이 안된다. 

    + shadow boundary의 style은 외부로 영향을 미치지 않는다. 

    + polyfill 이라고 브라우져가 지원하지않으면 기능을 지원할 수 있게 도와주는 스크립트 파일이라고 보면된다. 

       webcomponents.js 파일 같은 경우가 polyfill 파일이고 이것을 <script src="webcomponents.js"/> 하면 Shadow DOM에 대해 

       모든 브라우져에서 사용할 수 있다. 하지만 브라우져 버전은 확인해야 함. 


  - HTML Templates

    + <template id="name"> ... </template> 형태로 DOM에서 작용할 테그를 정의한다. 

    + <template> 태그에 있는 것은 DOM에 들어가지 않는다. 

    + 스크립트를 통해 DOM에 포함되는 구조이다. 

    + <template> 태그는 크롬과 몇개 브라우져만 지원하고 있다. 그러나 이것 역시 polyfill을 설치하면 모든 브라우져에서 수행가능함


  - Custom Elements

     + HTML에 새로운 태그를 정의하는 것이다. 마치 Angular의 Directive(지시자)와 유사하다. 

     + <element name="x-dowon"> ...</element> 으로 하면 <x-dowon> 태그를 사용할 수 있다. 

     + 앨러먼트의 lifecycle 콜백이 존재한다. 

     + 사용자 정의 앨러먼트를 만들기 위해 Shadow DOM, HTML Template 등이 필요한 것이다.

     + document에 register(<custom elements>)를 등록한다. 


  - HTML Imports 

     + <link rel="import" href="x-dowon.html"> 설정을 <head> 태그안에 둔다. 

     + 사용하려는 웹 컴포넌트의 확장자 .html을 import 타입으로 link 태그를 사용한다. 


    * 발표 자료 링크

    


    ** Web Components 스팩에 준수하여 개발된 Custom Element는 서로 조합하여 사용가능하다. 




Polymer와 Web Components


  - 구글이 웹 컴포넌트 스팩에 따라 구현한 것이 Polymer 이다. 파이어폭스는 X-Tags

  - Web Components의 구성요소를 지원하기 위해 Polymer는 다음과 같은 스택을 가진다. 

    + Native는 브라우져

    + Web Components 스팩 및 실제 필요한 몇가지 기능이 포함된 polyfill로서 platform.js 파일이 존재 

       현재는 WebComponents org의 webcomponents.js와 같은 명칭을 사용한다. 단 Chrome 36+ 부터는 polyfill이 전혀 필요없지만

       Web Components 기능을 구현하지 않은 브라우져들은 polyfill 파일을 포함해야 polymer.js를 통한 기능을 사용할 수 있다. 

    + Polymer 만의 API가 있는 polymer.js 코어

    + 구글의 API를 웹 컴포넌트로 만들어 놓은 Elements (Core, Paper)들이 있고 이를 토대로 Application을 만들 수 있는 길을 닦아 놓았다. 

   

  - Polymer와 Web Components에 대한 요약 정리

    


  - Polymer에서는 어떻게 쓰는지 바이들맨의 설명을 들어보자. (2014년 구글 I/O)

    + <polymer-element name="hi-dowon"> .. </polymer-element> 태그를 통해 Custom Elements를 만든다. 

    + <template> 태그를 사용하고 탬플릿안에서 {{ }} 머스태쉬를 사용해 Data Binding을 한다. (AngularJS 디렉티브의 @ 과 유사)

    + 물론 트위터 부트스트랩같은 UI F/W의 사용도 가능하다.(22분)

    + http://customelements.io/ 이나 http://component.kitchen/ 같은 곳에서 컴포넌트를 찾고 Bower를 통해 설치해서 사용한다. 

    + 구글의 다양한 서비스 API를 Polymer 기반 Custom Element로 만들어 놓았다. 

     


  - Material Design을 구현한 Polymer의 Paper Element 사용방법 (2014년 구글 I/O)

    + 머터리얼 디자인으로 웹/모바일 화면을 구현하고 싶다면 참조하자. 

    + RWD(Responsive Web Design, 반응형 웹 디자인)는 구글에서 Web Starter Kit 강좌에서 잘 설명해 주고 있다. 

    + Polymer Designer를 가지고 화면을 작성할 수 있다. (23분)

    + 하이브리드 앱 (Cordova)를 통한 예도 보여줌 (29분)

    + Layout : core-* element

       Material : paper-* element

       Theming : core-style

       Transition : core-animated-page

      을 통해 일반적으로 모바일에서 원하는 효과를 바로 얻을 수 있다. 

    + 그외 매튜 맥널티의 2014년 구글 I/O 마지막 동영상도 보자 

    


  폴리머의 장점은 재사용성에 있다고 본다. 디자이너와 같은 툴을 통해 미리 정의한 컴포넌트를 비즈니스에 맞게 가지고 있다면 사용자의 레벨에 따라 원하는 모바일/웹 환경을 쉽게 만들 수 있을 것이다. 따라서 반복적인 코드가 줄어 들 것이고 일관성있는 유지보수와 확장성을 보장할 것이다. 2년전 MEAN Stack을 통해 만들고 싶었던 것은 시각화 대시보드 저작도구 였다. HTML의 태그가 Custom Element처럼 표현이 되고 저작도구(Poly Designer)나 실시간에 해석되어 데이터를 실시간 차트로 보여줄 수 있는 BtoB 솔루션을 만들 수 있을 것이다. 이미 Flex 버전의 대시보드 저작도구를 개발해 보았지만 이제는 모바일/웹이 원활히 지원되는 기술로 바뀌어야 하기 때문에 Web Components는 나에게 더욱 필요한 머스트 아이템이 되겠다.  




<참조> 


  - 2013년 구글 I/O - Web Components Tectonic Shift

  - W3C의 Web Components Spec

  - Polyfill 개념

  - 2014년 구글 I/O - Web Components & Polymer (바이들맨의 Custom Element 정리)

  - Vanilla, X-Tags, Polymer 비교

  - Vulcanize : import 웹 컴포넌트 합쳐주는 도구

posted by 윤영식
2014. 12. 26. 11:48 Angular/Prototyping

새 술은 새 푸데에 넣어 보자. 모던 웹브라우져기반하에 구조적인 웹 애플리케이션을 개발할 수 있도록 해주는 Dart로 구글의 Web Component스펙 구현체인 Polymer를 시작하는 것도 재미 있을 것이다. Dart기반으로 개발을 하게 되면 Dart VM이 설치된 브라우져에서 수행이 되어야 하지만 현재는 Chromium + Dart VM을 결합한 Dartium에서만 수행이 되고 Dartium 은 별도로 설치해도 되지만 DartEditor를 설치하게 되면 포함되어 있어서 통합 개발환경하에서 디버깅 및 수행을 해볼 수 있다. 하지만 dart2js 도구를 통해 .dart 파일을 .js파일을 transpile할 수 있어 기존 모던 웹 브라우져에서 수행이 가능하다. 



 



Chrome Dev Editor 설치


  - 구글 I/O에서 소개한 크롬 개발 에디터는 다트와 웹컴포넌트로 만들어진 크롬앱이다. 설치를 한다.

  - 깃헙 사이트에서 Chrome Dev Editor를 볼 수 있다. 하기 내용은 Chrome App 으로 프로젝트를 생성한 경우이다. Dart 기반으로 생성이 되었다. 

    


  - 개발도구를 통해서 웹 컴포넌트를 추가하면서 개발도구를 업그레이드하는 과정을 보자. 흥미롭다. 

    


  - 현재는 개발자 프리뷰버전이 나와있어서 열심히 개밥(dogfood)을 먹으며 실험을 하고 있는 단계이다. 하지만 1년 2년이 지나면서 성능과 안정성 대중성이 확보되리라 생각한다. 물론 극히 개인적인 추론이지만 구글의 문화를 토대로 본다면 2013년부터 구글 I/O에서 계속 Angular, Polymer의 소개가 빠지지 않고 전략적으로 밀고 있다는 생각이 든다. 





Polymer 개념 잡기 


  - Web Component는 div soup에서 벗어나 사람이나 기계가 인지할 수 있는 의미있는 단어로 HTML을작성하고 이를 컴포넌트화 하는 것이다. 

    + 의미있는 단어로 HTML을 작성하기 위해 div 태그를 재정의 할 수 있어야 한다. 

       이는 Template을 통해 Custom Elements를 만든다

    + 컴포넌트화 하기위해서는 상태에 대한 것과 동작에 대한 것에 scope를 줄 수 있어야 한다. 

       상태 scope는 CSS를 Shadow DOM이라는 기념하게 Custom Element의 Template에만 적용되는 CSS를 작성할 수 있다. 

       동작 scope는 자바스크립트로 작성을 할 수 있고 Polymer를 사용하게 되면 Dart를 통해서도 가능하다. 

  - Web Components는 Angular의 Directive 지시자와 유사하지만 약간의 차이가 존재한다. UI와 스크립트 언어간의 two-way data binding하는 reactive programming은 동일하지만 그외의 부분은 지향하는 바가 틀리고 할 수 있는 영역이 틀리다. Polymer는 좀 더 강력한 웹 애플리케이션 UI를 빨리 만들 수 있도록 지원한다. 

    


  - 내가 좋아하는 애디 오스마니의 Polymer 소개 영상을 보자. 무려 한글로 해석되어 나온다. 

    





Polymer와 Dart의 관계


  - Dart는 구조적 웹 프로그래밍 언어로 구글에서 만들었다. 동적 타입 언어에 조금이라도 익숙하고 자바를 다루어 본 개발자라면 쉽게 배울 수 있는 언어이다. DartEditor는 Eclipse기반이고 import, inheritance, main() 등 자바에서 볼 수있는 것들을 잘 차용했다. 하지만 다트는 Strong static type 시스템인 자바와 틀리게 Strong dynamic type 시스템을 지향하고 Optional static type 적용이 가능하다. Web Component 스펙의 구현체인 Polymer와 Dart의 공통점은 모던 웹 브라우져에 돌아가는 애플리케이션을 빠르고 견고하게 만들 수 있도록 하는것을 지향한다는 것이다. Dart는 dart2js 도구를 제공하기 때문에 .dart를 .js로 변환하여 Dart VM이 설치되지 않은 브라우져에서 실행이 가능한 것이다. 따라서 Polymer에 Dart를 안해 볼 이유는 없어 보인다. 

  - Dartlang.org의 Polymer 페이지의 첫 문구이다. 위에서 이야기한 내용을 축약해서 표현해 놓았다. 

Use polymer.dart—a Dart port of Polymer—to build structured, encapsulated, client-side web apps with Dart and web components.


  - 구조

    + web 폴더가 있고 그안에 html 파일이 존재

    + pubspec.yaml은 Dart의 의존관계 및 메타정보에 대한 공식 설정 파일이다. 

      이것은 Node.js의 package.json이나 Bower의 bower.json과 동일하다. 

      


  - 의존관계로 polymer.dart를 설치한다. pubspec.yaml 설정 내역이다. 

dependencies:

  polymer: ">=0.15.1 <0.16.0"

transformers:

- polymer


  - Dart 기반으로 Polymer를 팔려면 우선 다음과 같이 진행하는 것이 맞다. 

    + 우선 Dart 개념을 잡아야 한다. 

    + 다음에 자바스크립트 기반으로 Polymer를 해본다. 

    + 마지막으로 다트 기반으로 Polymer를 접근한다. 

  - Polymer.dart와 AngularDart의 관계는 Polymer와 AngularJS의 관계와 유사하다. 서로 자바스크립트이냐 다트이냐의 차이일 뿐 상호 겹치는 부분의 Data Binding에서 상호 작용(Interoperation)할 수 있다. 


  만약 모던 웹 브라우져라는 제약이 존재 한다면 언어의 구분을 두지 말고 내가 원하는 웹 애플리케이션을 빠르고 견고하고 구조적으로 만들 수 있는지 고려해 시작하자. 감기로 인해 오늘은 여기까지... 




<참조>


  - 구글 I/O Polymer 소개 영상

  - Dartium 소개

  - Angluar와 Polymer 사이의 Data Binding

  - Reactive Programming Wikipedia

posted by 윤영식
2014. 12. 24. 17:15 Languages/Python

처음으로 새로운 프레임워크를 접하게 되었을 때 어떻게 시작해야할지 막막하다. 그럴땐 공부할 꺼리들을 정리해 보고 시작하자. 새롭게 시작할 AngularDart의 컨텐츠를 정리해 보자. 






AngularJS 개발자가 AngularDart 개발하기 


  - AngularDart의 상당 부분이 실은 AngularJS v2.0에 많은 영향을 미쳤다. (미스코의 말)

    + AngularJS개발자를 위한 AngularDart 이해하기

  - Dartlang을 모르고서 AngularDart를 보면 안되겠죠?  

  - UI Framework과 연동해서 웹 애플리케이션을 만들어 본다. (깃헙 소스)

    


  - 코드랩을 따라한다.

    + 예제 데모를 돌려보면 최신 IE 11, FF, Safari, Chrome에서 잘 돌아감. 

    + HTML의 디렉티브는 AngularJS와 거의 같음. 코드만 .dart 로 작성함 

  - 개발하며 API를 참조한다.





AngularDart와 Polymer 연동하기


  - 우선 AngularDart 소개영상과 25분부터 이어지는 Polymer.Dart를 보자 

    + 보고 있으면 아마도 ng-conf 2014에서 소개한 Angular v2.0 영상의 14분 부터 보면 뭔가 떠오를지 모르겠다. 

    

 

  - 첫번째 영상에서 Web Component 개념을 이야기하는 Polymer.dart를 다시 보자. 

  - 다시 정리하고 있는 Parsley의 Web Component & Dart 동영상을 보자

  - 따라하기 하며 Dart와 Polymer.dart를 연결해 보기 


계속해서 업데이트 예정...




<참조> 


  - Dart와 Web Component에 대한 다른 영상

  - 미스코 헤베리의 AngularDart를 만든 이유 

The Angular team's mission is to make building web-applications easy on the web. We want to support as many languages as possible.

AngularJS supports: JavaScript and through transpilation CoffeeScript and TypeScript.

AngularDart obviously supports Dart. 

1) Dart is significantly different from JavaScript that transpilation approach would not create the experience we were looking for, for this reason we have rewritten it. 

2) Dart has Types, and Type annotations, and so while rewriting AngularDart we have chose to take advantage of these language features. 

3) We have also learned from our mistakes on AngularJS and taken the opportunity to correct them, such as much improved Directive API. Finally we have take advantage of the latest browser technologies and based AngularDart on top of Shadow DOM.

4) All of the learnings we have gained in building AngularDart, will be applied back to AngularJS v2. This is only expected since AngularDart is younger than AngularJS.

Angular is a philosophy on how applications should be built and we wanted to make the question of language choice orthogonal to your choice of using Angular. Any web-language you choose, there is an Angular you can use with it.



'Languages > Python' 카테고리의 다른 글

[Dart] Dart 배우는 방법  (0) 2014.12.31
[Dart] 다트 언어 개념잡기  (0) 2014.12.24
posted by 윤영식
2014. 12. 24. 14:53 Languages/Python

빠르게 메타지식을 흡수해 변환에 적응하는 능력을 지적 겸손이라 한다. 태도의 겸손이 아닌 내가 아는 것이 전부가 아니고 더 낳은 방법과 기술이 있다면 메타지식을 빠르게 흠수할 수 있는 능력이 필요한 시대가 되었다. 새로운 웹 개발언어로 성능과 생산성 증대를 목표로 하는 Dart에 대해 공부를 해본다.






중요 개념 


  - 모든 변수는 Object 이다. 

  - 정적 타입과 동적(dynamic) 타입이 가능하다   

  - 정적 타입 오류를 컴파일 타임에 알려준다

  - main() 펑션이 있다

  - public, protected, private 같은 것이 없고 _ (underscore)로 표현한다 

  - warning 은 프로그램이 수행 안될지도 모른다 이지만 수행을 막지는 않는다. 

    error가 컴파일 타임이 나면 수행할 수 없고 런타임에 발생하면 exception이 발생한다.  

  - 런타임 모드는 production 과 checked 두가지다. 개발시에는 checked 모드로 사용한다. 

     production 모드에서는 assert 구문을 무시한 최적화를 통해 성능을 향상시켜준다. 

  - 키워드 

   

    1 : built-in indentifier : 자바스크립트를 다트로 포팅을 쉽게 해준다. 

    2 : 제한적인 예약어로 비동기 지원과 관련이 있다. 

    



변수 (Variables)


  - 예 : 'Peter' 값을 가지는 String 객체의 레퍼런스 주소값을 name이라는 변수가 가지고 있다. 

var name = 'Peter';


  - 최기화 되지 않은 변수는 null 초기값을 갖는다. 숫자가 초기값이 없어도 null 초기값을 갖는다. 

    assert 구문은 production 모드에서 무시된다. 만일 assert 구문이 true가 아니면 exception을 던진다. 

int lineCount;

assert(lineCount == null);


  - 옵셔널 타입으로 String name = 'Bob'으로 직접 지정해 줄 수도 있지만 타입 스타일 가이드에 따라 var를 사용한다. swift와 유사함 

  - final은 변수의 값을 변경하고 싶지 않을 경우 var 대신 사용한다. const는 수치값을 지정한다. 

  - numbers, strings, booleans, lists, maps, symbols 관련 빌트인 타입을 가지고 있다. (예제 참조)

    + numbers : int, double 있고 이들은 num의 서브타입이다. 다트의 int와 자바스크립트 int는 틀리다. 다트 int는 arbitrary-precision integer

    + strings : UTF-16 코드를 따르고 ''  또는 "" 사용가능. 'hi peter ${expression}' 식으로 문자안에 ${} 표현가능. swift와 유사함

    + booleans : bool 타입으로 true, false를 값을 가져야 하고 자바스크립트와 틀리다. 즉, var name='pter'; if(name)하면 false이다. 

    + lists : 다트의 배열은 List 오브젝트이다. 인덱싱은 0부터 시작한다. GenericsCollections을 살펴보자 

    + maps : key-value에 대해 Map 오브젝트를 사용한다. JSON처럼 literal 지정 

    + symbols : Symbol 오브젝트를 통해서 operator와 identifier를 표현한다. 




펑션 (Functions)


  - 예 : 스타일 가이드에 따라 파라미터와 리턴 타입 지정한다. 

// 파라미터와 리턴 타입을 명시하는게 스타일 가이드 

void printNumber(num number) { 

  print('this is $number');


// 하지만 생략도 가능 

printNumber(number) 

  print('this is $number');

 


  - => expr;{ return expr; } 표현과 같다. coffeescript 같은 축약형 좋다. 하기 표현은 위 표현과 동치 

printNumber(number) => print('this is $number');


  - 옵션널 파라미터

    + 기본 설정 : enable(bool flag1, bool flag2) { ... }

    + Optional named parameter는 paramName: value로 지정 

       예) enable({bool flag1: false, bool flag2: true}) { ... } 사용 enable(flag1: true)

    + Optional positional parameter는 [] 마크를 사용

       예) say(String from, String msg, [String device]) { ... } 사용 say('hi', 'peter') 또는 say('hi', 'peter', 'ios')

  

  - 애플리케이션은 최상위 레벨에서 main() 펑션를 갖는다. 애플리케이션의 진입점역할을 한다. 자바와 유사함

    .. 오퍼레이터는 cascade operator이다. 즉, 이어서 호출한다. 

void main() {

  querySelector('#peter')

    ..text = 'Hi dowon'

    ..onClick.listen(reservedText);


  - Functions as first-class objects 이다. 펑션을 다른 펑션에 파라미터로 전달하거나 리턴하는 것이 가능. 이건 자바스크립트부터 쭉... 

printElm(element) {

  print(element);

}


var list = [1,2,3];

list.forEach(printElm); // printElm을 파라미터로 전달 


  - 자바스크립트는 function 레벨에서 lexical scope를 갖듯 다트도 lexical scope를 갖는다. 즉, 변수의 스코프가 정적으로 정해진다. (단, 자바스크립의 this는 호출되는 시점에 결정되므로 이부분에 틀림. 아래 참조 링크를 보자) 다트는 curly raches outwards를 따른다. (자바스크립트는 변수에 var를 줌으로 로컬 변수 스코프임을 지정한다) 

  - lexical closures는 lexical scope안의 변수를 접근하는 펑션 오브젝트이다. 

closure is a function object that has access to variables in its lexical scope, even when the function is used outside of its original scope.


  - 모든 펑션은 리턴값을 갖고 지정하지 않으면 return null; 이다. 




연산자 (Operators)


  - 연산자 종류 

    


  - 타입 테스트 오퍼레이터 

    



제어 흐름 (Control Flow Statement)


  - if(){ ... } else if() { ... } else { ... }

  - for ( 초기값 ; 비교 ; 증분 ) { ... } 또는 for in 

  - while() { ... } 또는 do { ... } while ()

  - while에서 break, for 에서 continue 

  - switch ~ case ~ default




예외처리 (Exceptions)


  - 다트의 예외는 unchecked exception 이다. 

  - 다트는 ExceptionError 타입을 제공한다. 

  - throw 하면 에러를 일으킨다. 

  - on catch 으로 exception을 catch 하고 전파되는 것을 막는다. 

try {

  aa();

} on OutofException {  // known exception

  bb();

} on Exception catch (e) { // anyting else that is an exception

  print('exception is: $e');

} catch (e) {

  print('really unknown : $e');

}

 

  - finally : finally가 수행된 후에 exception이 전파된다 




클래스 (Classes)


  - 다트는 객체지향 언어이다. 

  - new 키워드로 클래스의 인스턴스인 오브젝트를 생성한다. 

  - 클래스는 펑션과 데이터를 멤버로 갖고 특히 오브젝트의 펑션을 메소드라 부른다. dot(.)로 호출한다. cascade operator(..)은 싱글 객체의 멤버를 연속적으로 호출할 때 사용한다.

  - 생성자는 클래스와 같은 이름을 자고 this는 현재 인스턴스를 가르킨다. 자바와 유사

  - 생성자를 선언하지 않으면 아규먼트 없는 기본 생성자가 자동 제공됨. 자바와 유사 

  - 생성자는 상속되지 않는다. 

class Point {

  num x;

  num y;


  Point(this.x, this.y);

}


  - get, set 키워드를 통해 프로퍼티를 만들 수 있다. 

class Rectangle {

  num left;

  num top;


  Rectangle(this.left, this.top);


  num get right   => left;

         set right(num value) => left = value - left;

}


  - abstract class를 만들 수 있다. 상속은 extends를 사용함.  자바와 유사 

abstract class Door { 

  void open();

}


  - 연산자도 오버라이드 할 수 있음 

  - 모든 클래스인 암묵적으로 interface를 정의할 수 있다. 만일 A 클래스가 B의 구현체를 상속받지 않고 B의 API만을 사용하고 싶을 경우 implements 키워드를 사용한다. 자바에는 없는 재미난 부분

// A person. The implicit interface contains greet().

class Person {

  final _name;          // In the interface, but visible only in this library,

  Person(this._name);   // Not in the interface, since this is a constructor.

  String greet(who) => 'Hello, $who. I am $_name.'; // In the interface.

}


// An implementation of the Person interface.

class Imposter implements Person {

  final _name = "";      // We have to define this, but we don't use it.

  String greet(who) => 'Hi $who. Do you know who I am?';

}


greetBob(Person person) => person.greet('bob');


main() {

  print(greetBob(new Person('kathy')));

  print(greetBob(new Imposter()));

}


  - extends 키워드로 상속을 하고 super는 부모 클래스를 가르킴. 자바와 유사

  - 상속시 부모 메소드에 대한 @override를 명시적으로 사용해 오버라이딩이 가능하다. 

  - 클래스에 @proxy라고 하면 @override시에 warning을 준다. 

  - 다중 상속시에 mixin 개념의 클래스 코드 재사용이 도입. with 키워드를 사용한다. mixin 할때는 upser, 생성 선언이 없다. 

class Musicain extends Performer with Musical, Aggressive, Demented { 

  ...

}


  - 클래스 소속 메소드와 변수는 static 키워드를 사용한다. 자바와 유사




제네릭 (Generics)


  - 다트에서 타입은 옵셔널이다. 의도를 명확히 하기 위해 공식적으 타입 파라미터를 같는 타입이다. (generic == parameterized) type

    예에서 문자로 지정을 한다는 의도를 분명히 한다. 

var names = new List<String>();

names.addAll(['Seth', 'Kathy', 'Lars']);

// ...

names.add(42); // Fails in checked mode (succeeds in production mode).


  - type variables로는 통상 E, T, S, K, V 같은 단일 문자를 갖는다. 

  - 제네릭은 코드의 중복을 방지해 준다. 상속하여 구현 하면 됨 

// Object 경우 

abstract class ObjectCache {

  Object getByKey(String key);

  setByKey(String key, Object value);

}


// String 경우 

abstract class StringCache {

  String getByKey(String key);

  setByKey(String key, String value);

}


// 하나로 줄여줌 

abstract class Cache<T> {

  T getByKey(String key);

  setByKey(String key, T value);

}


  - Collection literal에도 사용가능하다. 

var names = <String>['Seth', 'Kathy', 'Lars'];

var pages = <String, String>{

  'index.html': 'Homepage',

  'robots.txt': 'Hints for web robots',

  'humans.txt': 'We are people, not machines'

};


 


라이브러리와 가시성 (Libraries and visibility) 


  - import, part, library 지시자(Directives) 사용한다. 

  - 라이브러리는 Pub Package and Asset Manager인 pub 툴로 패키지를 사용 배포한다. 

  - import 'dart:html';  형식으로 import는 URI 형시그로 라이브러리를 지정한다. 

  - 빌트인은 'dart:xxx' 로 시작한다. 

  - pub 툴 배포로 제공되는 것은 import 'package:<file path>'; 로 지정한다. 예) import 'package:utils/utils.dart';

  - as로 aliasing이 가능 예) import 'package:lib2/lib2.dart' as lib2; 

  - show, hide 통해 라이브러리 일부만 가져오기 가능 예) import 'package:lib2/lib2.dart' show foo;

  - 라이브러리의 Lazily loading이 가능하다. deferred as 키워드를 사용한다. AngularJS의 $q를 보자  

    + 애플리케이션 초기 시작시간을 줄이기 위해 사용

    + A/B 테스트를 수행하기 위해

    + 사용이 적은 것들 로딩할 때 

    예) import 'package:deferred/hello.dart' deferred as hello;  하기에 then 구문으로 비동기적 호출을 한다.

hello.loadLibrary().then((_) {

  hello.printGreeting();

});


  - 다른 방법으로는 async 키워드를 사용한다. loadLibrary()는 Future를 리턴한다. 

greet() async {

  await hello.loadLibrary();

  hello.printGreeting();

}


  - library <라이브러리명칭>; 으로 사용한다. part는 라이브러리의 첨부된 파일을 지칭한다. 

library ballgame;   // Declare that this is a library named ballgame.


import 'dart:html'; // This app uses the HTML library.


part 'ball.dart';  // ballgame의 일부이다. 


 


비동기 지원 (Asynchrony support)


  - async 와 await 키워드를 사용한다. 

  - 다트 라이브러리는 Future 오브젝트를 리턴하는 펑션셋을 가지고 있다.  

  - dart 또는 dartanalyzer에서 async 지원을 위해 옵션을 주어야 한다. DartEditor (Eclipse기반)에도 넣어줌 

    

dart --enable-async async_await.dart

dartanalyzer --enable-async async_await.dart


  - async 펑션선언 

check() async {

  //...

}


look() async => //...


  - await <expression> 에서 expression은 타입 Future를 가지고 있고 이는 오브젝트를 리턴하기 위한 promise이다. 리턴된 오브젝트가 유효할 때까지 실행은 멈춘다. 




Typedefs


  - 다트에서 펑션, 문자, 숫자 모두 오브젝이다. 

  - typedef 또는 function-type alias 는 필드나 리턴타입을 선언할 때 사용할 수 있는 펑션타입에 이름을 준다. 

// f를 compare로 할당할 때 int f(Object, Object)의 타입정보가 사라진다.

class SortedCollection {

  Function compare;


  SortedCollection(int f(Object a, Object b)) {

    compare = f;

  }

}


// typedef로 펑션타입을 정의한다.

typedef int Compare(Object a, Object b);


class SortedCollection {

  Compare compare;


  SortedCollection(this.compare);

}




메타데이터 (Metadata)


  -  메타데이터는 추가적인 정보를 주기위해 사용한다. @ 키워드로 애노테이션을 사용한다. 

  - @deprecated, @override, @proxy 등의 메타데이터 애노테이션을 사용한다. 

  - 커멘트는 한줄 // 사용하고 다중은 /* */을 사용한다. 




참조 

  

  - 다트 기초 

  - 구글 취업이 원하는 인재상 : 지적 겸손에 대하여

  - 자바스트립트에서의 lexical scope와 this의 의미 번역 (원문)

  - 컴퓨터 사이언스에서 Lexical Scope 위키피디아

  - Dart Slides 및 동영상

  - Dart VM으로 서버 만들기 Framework 종류

'Languages > Python' 카테고리의 다른 글

[Dart] Dart 배우는 방법  (0) 2014.12.31
[AngularDart] 앵귤러다트 배우는 방법  (0) 2014.12.24
posted by 윤영식

배너 밑으로는 선전하고 싶은 상품 목록 4개를 열거한다. 이때 반응형 웹 디자인의 그리드(Grid)를 적용해 본다. 




화면 분할


  - WEB-INF/templates/layout/home.html 템플릿의 내용이 많아지면 partial html로 분리하여 include하는 방식을 취한다

  - 우선, Homepage Banner Ad Carousel 부분을 <th:include> 처리하고 Product 목록 부분도 <th:include> 처리해 관리한다. 

  - 기존 화면 

   


  - 변경 화면

    + 박스 테두리 CSS를 적용한다

    + 각 박스 테두리별로 반응형 그리드를 적용한다  

   

  - WEB-INF/templates/layout/home.html 내역중 Carousel에 대한 부분과 product 목록에 대한 부분을 WEB-INF/templates 폴더 밑에 main/partials 폴더를 새롭게 만들고 banner-caruosel.html 과 product-list.html 을 생성하고 기존 내역을 옮긴다. 

  - content의 contentType인 "Homepage Featured Products Title" 인 목록을 뿌려주는 것이다. 

  - layout 폴더에서 main 폴더로 옮기는 이유는 해당 main 폴더 영역에 있는 부분이 계속 변경되기 때문이다. 즉, 다른 페이지로 이동해도 nav와 footer는 고정되어 있다. 

// home.html의 과거 내역 


<blc:content contentType="Homepage Featured Products Title" />    

<div th:if="${contentItem !=null and contentItem['messageText'] !=null}" class="title_bar" th:text="${contentItem['messageText']}"></div>


<ul id="products" class="group">

    <li th:each="product : ${products}" th:object="${product}" th:include="catalog/partials/productListItem" class="product_container"></li>

</ul>



// 신규 layout/home.html 일부 내역 


    <div th:include="main/partials/banner-carousel" />

    

    <div class="section">

        <div th:include="main/partials/featured-products" />

    </div>



// main/partials/featured-products.html


    <div class="container">

   

          <div class="row">

          <blc:content contentType="Homepage Featured Products Title" />  

             <div th:if="${contentItem !=null and contentItem['messageText'] !=null}" 

                  class="col-lg-12 col-md-12 col-sm-12 col-xs-12 featured-title" 

                  th:text="${contentItem['messageText']}"></div>

       

              <div th:each="product : ${products}" 

                   th:object="${product}" 

                   th:include="catalog/partials/productListItem" 

                   class="col-lg-3 col-md-3 col-sm-6 col-xs-6">

              </div>

          </div>

          

    </div>


  - class="col-lg-3 col-md-3 col-sm-6 col-xs-6" 을 적용해서 데스크톱에서는 4개씩 상품이 보이고 테블릿 이하는 2개씩 상품이 보임




Product Item 그리드 구성 


  - th:include="catalog/partials/productListItem" 에서 기존 productListItem.html 의 CSS를 하기와 같이 다시 적용한다 

    + max-width: 320px; 를 주어 박스의 최대 크기를 지정한다. 

// /webapp/css/style.css 일부 내역 


/************************************/

/* featured product list  */

/************************************/

.thumbnail {

max-width: 320px;

display: block;

padding: 5px;

margin-bottom: 10px;

line-height: 1.5;

background-color: #fff;

border: 1px solid #ddd;

border-radius: 4px;

-webkit-transition: border .2s ease-in-out;

-o-transition: border .2s ease-in-out;

transition: border .2s ease-in-out;

}


.thumbnail .content {

padding: 3px;

font: 13px/18px 'BryantLGRegular';

color: #655c5a;

overflow: hidden;

}


.thumbnail .content .title {

font: 15px/18px 'BryantLGMedium';

margin-bottom: 7px;

color: #222222;

height: 36px;

max-height: 36px;

}


.thumbnail .content .desc {

padding: 3px;

font: 13px/18px 'BryantLGLight';

color: #655c5a;

overflow: hidden;

height: 72px;

max-height: 72px;

}


.thumbnail .new_badge {

width: 60px;

height: 60px;

background: url('../img/badge-new.png') no-repeat;

text-indent: -9999px;

position: absolute;

top: -10px;

left: -1px;

z-index: 20;

}


.thumbnail .image {

margin-bottom: 10px;

overflow: hidden;

position: relative;

z-index: 10;

}


.thumbnail .image .price {

position: absolute;

background-color: black;

color: white;

opacity: 0.8;

padding: 10px 20px;

font: 16px/16px 'BryantLGMedium';

font-weight: 600;

bottom: 5px;

right: 5px;

}


  - 적용한 productListItem.html 의 내용은 하기와 같다.

<div class="thumbnail">

<div th:if="*{featuredProduct}" class="new_badge">New!</div>


<div class="image">

<a th:href="@{*{url}}">

    <img th:if="*{media['primary']}" blc:src="@{*{media['primary'].url} + '?browse'}" th:alt="*{name}" />

    <div class="price" th:if="${#object instanceof T(org.broadleafcommerce.core.catalog.domain.ProductBundle)}">

        <div blc:price="*{salePrice}" th:if="*{onSale}" th:classappend="*{defaultSku.onSale}? 'sale'"></div>

        <div blc:price="*{retailPrice}" th:classappend="*{onSale}? 'has-sale'"></div>

    </div>

    <div class="price" th:unless="${#object instanceof T(org.broadleafcommerce.core.catalog.domain.ProductBundle)}">

        <div blc:price="*{defaultSku.salePrice}" th:if="*{defaultSku.onSale}" th:classappend="*{defaultSku.onSale}? 'sale'"></div>

        <div blc:price="*{defaultSku.retailPrice}" th:classappend="*{defaultSku.onSale}? 'has-sale'"></div>

    </div>

    </a>

    </div>

    

<div class="content">

  <div class="title" th:text="*{name}">Product Name</div>

<p class="desc" th:utext="*{longDescription}">description</p>

<p> 

<div th:class="*{'productActions productActions' + id}"

    th:with="checkInventory=*{defaultSku.inventoryType?.type == 'CHECK_QUANTITY'},

              availableInventory=${checkInventory ? #object.defaultSku.quantityAvailable != null and #object.defaultSku.quantityAvailable != 0 : true},

              inCart=${cart.containsSku(#object.defaultSku) and #lists.isEmpty(product.productOptions)}">

    <div th:if="${checkInventory and !availableInventory}" class="out_of_stock">

        <a disabled="disabled" class="inCart">Out of Stock</a>

    </div>

    <div class="btn btn-default" th:classappend="${!inCart}? ' hidden'" th:if="${#lists.isEmpty(product.productOptions)}">

        <a class="modalcart inCart" th:href="@{/cart}"><span th:text="#{product.inCart}">In Cart!</span></a>

    </div>

    <div class="add_to_cart" th:classappend="${inCart or !availableInventory}? ' hidden'">

        <blc:form method="POST" th:action="@{/cart/add}">

            <input type="hidden" name="productId" th:value="*{id}" />

            <input type="hidden" name="quantity" value="1" />

            <input type="hidden" name="hasProductOptions" th:value="*{!#lists.isEmpty(productOptions)}" />

            <input type="submit" class="btn btn-primary" th:value="#{product.buyNow}"/>

        </blc:form>

    </div>

</div>

</p>

    </div>

    

</div>


<div style="display: none;" th:id="*{'productOptions' + id}" class="product-options modal">

    <h3 th:text="*{name}"></h3>

    <div class="product-options" th:substituteby="catalog/partials/productOptions"/>

    <input type="button" class="addToCart" th:value="#{product.buyNow}" />

</div>


화면 구성이 되었다면 다음으로 2단 메뉴 구성을 해보자 

posted by 윤영식

DemoSite에서 제공하는 랜딩 페이지의 중앙에는 마케팅 제품 한개만을 디스플레이한다. 이를 여러개의 마케팅 제품을 Carousel로 변경하는 작업을 해본다. 




Carousel HTML 추가


  - 원래 화면으로 SHIRT SPECIAL 이미지가 고정이다.

    


  - 변경된 화면으로 Carousel을 적용한다. 

    + Twitter Bootstrap의 carousel을 적용

    + 기존 제품을 두번째에 배치

    


  - HTML에서 메인 마케팅 제품의 <blc> 태그 내역음 하기와 같다

    + <blc:content> 태그의 contentType="Homepage Banner Ad"의 값이 키가 되어 content의 데이터를 MySQL에서 찾음

    + 반환값인 contentItem 객체를 통해 Thymeleaf 템플릿엔진은 HTML을 생성해줌

    + Twitter Bootstrap의 carousel을 추가하고 첫번째에 배너를 넣고 다음 아이템(보라색) 두번째에 틀린 배너를 넣음

       contentType인 Homepage Banner Ad2 라는 이름임 

// 원본 소스 

<nav th:substituteby="layout/partials/nav" />

            

<blc:content contentType="Homepage Banner Ad" />   

<div id="banners" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}">

    <a th:href="@{${contentItem['targetUrl']}}"><img blc:src="@{${contentItem['imageUrl']}}" /></a>       

</div>



// 수정 소스 

<div th:include="layout/partials/nav" />

       

<div id="myCarousel" class="carousel slide">

    <!-- Indicators -->

    <ol class="carousel-indicators">

        <li data-target="#myCarousel" data-slide-to="0" class="active"></li>

        <li data-target="#myCarousel" data-slide-to="1"></li>

        <li data-target="#myCarousel" data-slide-to="2"></li>

    </ol>


    <!-- Wrapper for slides -->

    <div class="carousel-inner">

        <div class="item active">

            <blc:content contentType="Homepage Banner Ad" />

            <div class="fill" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}" >

              <a th:href="@{${contentItem['targetUrl']}}"><img style="height:100%; width:100%" blc:src="@{${contentItem['imageUrl']}}" /></a>  

            </div>

            <div class="carousel-caption">

                <h1></h1>

            </div>

        </div>

        <div class="item">

            <blc:content contentType="Homepage Banner Ad2" />

            <div class="fill" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}" >

              <a th:href="@{${contentItem['targetUrl']}}"><img style="height:100%; width:100%" blc:src="@{${contentItem['imageUrl']}}" /></a>  

            </div>

            <div class="carousel-caption">

                <h1>This is Homepage Banner Ad2 Test</h1>

            </div>

        </div>

        <div class="item">

            <div class="fill" style=""></div>

            <div class="carousel-caption">

                <h1>Additional Layout Options at <a href="http://startbootstrap.com">http://startbootstrap.com</a>

                </h1>

            </div>

        </div>

    </div>


    <!-- Controls -->

    <a class="left carousel-control" href="#myCarousel" data-slide="prev">

        <span class="icon-prev"></span>

    </a>

    <a class="right carousel-control" href="#myCarousel" data-slide="next">

        <span class="icon-next"></span>

    </a>

</div>


  - Carousel을 구동하는 자바스크립트를 추가함 

    + WEB-INF/templates/layout/partials/footer.html안에 main.js를 추가함. 메인 페이지 하단에 자바스크립트를 추가해줌 

    + webapp/js 폴더 밑에 main.js 를 추가하고 carousel 자바스크립트를 초기화하고 화면간 이동시간을 설정함

// footer.html 

 <blc:bundle name="heatclinic.js" 

                mapping-prefix="/js/"

                files="main.js,

                       BLC.js,

                       heatClinic.js,

                       cartOperations.js,

                       checkoutOperations.js,

                       globalOnReady.js,

                       manageAccountOperations.js,

                       reviewOperations.js" />



// js/main.js

$('.carousel').carousel({

  interval: 3000

})




Homepage Banner Ad2 추가하기


  - Homepage Banner Ad가 추가된 위치를 Admin에서 화인할 수 있다.

    + DemoSite에 보면 admin sub-module이 있고 Ant를 통해서 실행할 수 있다. 

    + http://localhost:8081/admin 으로 접속해서 id:admin, pwd:admin으로 접속한다.

    + 관리페이지의 Content -> Content Items를 보면 아이템 목록이 나오고 "Content Type"이 Homepage Banner Ad가 언어별로 등록됨

    + 즉, <blc:content> 태그의 contentType이 데이터 조회를 위한 파라미터 키이고 Homepage Banner Ad가 값임.

    


  - 최초에 DemoSite를 수행할 때 src/main/resources/runtime-properties/development.properties는 하기와 같다 

    + create-drop 설정은 DemoSite 서버(jetty)를 기동할 때 기존 테이블을 전부 drop 하고 새롭게 생성하고 데이터를 넣어줌 

    + 한번 생성된 이후 다시 drop하지 않고 DemoSite를 기동하고 싶으면 update로 변경함 

// 기존 설정 

blPU.hibernate.hbm2ddl.auto=create-drop


// 변경 설정

blPU.hibernate.hbm2ddl.auto=update


  - 결국 DemoSite 기동할 때 insert 구문을 통해 Homepage Banner Ad를 넣고 있으므로 Homepage Banner Ad2 값을 넣을 수 있음

    + sql 파일은 core sub-module의 src/main/resrouces/sql밑에 존재함 

    + 관련 sql은 load_content_structure.sql 과 load_content_data.sql 이다 

    + content_structure는 원화 기준, 언어 기준, 화면 템플릿의 논리적 그룹핑 명칭 등록 및 4단계를 거쳐 structure를 만들어준다 

// load_content_structure.sql 안에 보라색 내역 Homepage Banner Ad2를 추가함


---------------------------------------------------------------------------------------------------------------------------

-- Structured Content Step 4:   Create Types (These represent areas on a page or general types:  e.g 'Homepage Banner Ad')

---------------------------------------------------------------------------------------------------------------------------

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (1, 'Homepage Banner Ad', NULL, 1);

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (2, 'Homepage Middle Promo Snippet', NULL, 2);

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (3, 'Homepage Featured Products Title', NULL, 3);

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (4, 'Right Hand Side Banner Ad', NULL, 1);


-- by ysyun

INSERT INTO BLC_SC_TYPE (SC_TYPE_ID, NAME, DESCRIPTION, SC_FLD_TMPLT_ID) VALUES (5, 'Homepage Banner Ad2', NULL, 1);


    + content_data는 컨텐트의 url, image 등의 세부 내역이 담겨져 있다. 

    + 원본은 3개의 Banner가 우선순위가 있게 등록되어 있는데 Homepage Banner Ad2를 새로운 배너 우선순위 1로 해서 등록한다.

    + 기존 베너에 있던 Buy One Get One을 Homepage Banner Ad2에 배정한다. 

    + 세번째 Carousel을 등록하고 싶다면 Homepage Banner Ad3를 structure에 등록해서 하기 과정에 sql을 추가하면 끝! 

    + 이미지는 webapp/img/banners 폴더에 존재함 

// load_content_data.sql 에서 보라색 부분을 추가한다.


---------------------------------------------------

-- HOME PAGE BANNER

---------------------------------------------------

-- Content Item

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (100, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Buy One Get One - Twice the Burn', FALSE, 5, 'en', 1);

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (101, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Shirt Special - 20% off all shirts', FALSE, 1, 'en', 1);

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (102, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Member Special - $10 off next order over $50', FALSE, 5, 'en', 1);


-- by ysyun

INSERT INTO BLC_SC (SC_ID, CREATED_BY, DATE_CREATED, DATE_UPDATED, UPDATED_BY, CONTENT_NAME, OFFLINE_FLAG, PRIORITY, LOCALE_CODE, SC_TYPE_ID) VALUES (103, 1, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 1, 'Buy One Get One - Twice the Burn', FALSE, 1, 'en', 5);


-- Fields

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (1, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/buy-one-get-one-home-banner.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (2, CURRENT_TIMESTAMP, 'targetUrl', 1, '/hot-sauces');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (3, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/shirt-special.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (4, CURRENT_TIMESTAMP, 'targetUrl', 1, '/merchandise');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (5, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/member-special.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (6, CURRENT_TIMESTAMP, 'targetUrl', 1, '/register');


-- by ysyun

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (7, CURRENT_TIMESTAMP, 'imageUrl', 1, '/img/banners/buy-one-get-one-home-banner.jpg');

INSERT INTO BLC_SC_FLD (SC_FLD_ID, DATE_CREATED, FLD_KEY, CREATED_BY, VALUE) VALUES (8, CURRENT_TIMESTAMP, 'targetUrl', 1, '/hot-sauces');


-- Field XREF

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (100, 1, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (100, 2, 'targetUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (101, 3, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (101, 4, 'targetUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (102, 5, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (102, 6, 'targetUrl');


-- by ysyun

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (103, 7, 'imageUrl');

INSERT INTO BLC_SC_FLD_MAP (SC_ID, SC_FLD_ID, MAP_KEY) VALUES (103, 8, 'targetUrl');


  - sql 추가하고 create-drop으로 놓은 다음 DemoSite를 제구동하면 Admin에서 하기와 같이 나온다. 

  


베너를 Carousel로 변환하여 볼 수 있을 것이다. 다음은 2 level Menu로 변경하는 과정을 살펴보자. 



참조 


  - Broadleaf DemoSite 소스

posted by 윤영식
2014. 12. 13. 11:59 AI Deep Learning

Recommanding Items 에서 원본 데이터에서 필터링을 통해 데이터 셋 만들기



아이템 추천 


  - people, item, score 를 설정한다 

    + 스코어 : 스코어가 여러개에 대한 데이터셋 벡터 수치화 하기 

  - dictionary -> transform matrix (dataset) -> find top match

    + 딕셔너리 ?

    + 데이터셋으로 만들고 최상위 매칭을 찾음 

  - build dataset -> recommending neighbor and link 




아이템 기반 필터링 


  - 사용자 기반 필터링과 대비 

  - 평가 점수를 통해 근접한 추천 아이템을 골라내기 

    + 질문과 답이 있는 것 (Supervised ML) -> 알고리즘으로 돌려 -> 추천 아이템을 찾아냄 

    + 질문 : 나에게 추천할 만한 영화는?

    + 답 : 내가 본 영화 평점, 사람들이 평가한 평점을 통해 추천

    + MovieLens 알고리즘 : http://grouplens.org/datasets/




ML 프로세스


  - 원본 데이터를 필터링을 통해서 데이터 셋을 만든다. 

  - 데이터 셋의 값에서 유사도(similarity)를 구한다. ex) 피어슨 (Pearson)

  - 값 X 유사도  = 정확도 (precision)

  - 필터링으로 통해 나온 데이터셋에서 ML 알고리즘을 돌려 추천 값을 얻는다.  





'AI Deep Learning' 카테고리의 다른 글

[ML] 7주차 - 6장 문서 필터링  (0) 2015.02.07
[ML] 6주차 - 5장 최적화  (0) 2015.01.31
[ML] 4주차 - 군집하기  (0) 2015.01.03
[ML] 2주차 - 추천하기  (0) 2014.12.06
[ML] 1주차 - 시작하기  (0) 2014.11.22
posted by 윤영식
2014. 12. 6. 12:30 AI Deep Learning

Chapter8 - Making Recommendations. Recommandation Engine


예로 영화 추천 시스템일 경우 사람들끼리 상관관계 거리를 계산해서 가까운 사람들의 소그룹을 만들고 소그룹에서 A 사용자가 안보았으나 B 사용자가 본 영화를 추천해 준다. 즉, 선호도가 비슷한 사람들의 소그룹을 만들고 여기서 안본 영화들을 추천해 주는 것이다. 선호도 그룹을 찾는 방법에는 유클리디안 거리와 피어슨 상관관계 기법이 사용된다. 여기에는 거리(Distance)와 계수(Coeffiecient)이야기가 나온다. 


Collaborative Filtering 

  - 큰 그룹을 찾아서 나와 유사한 경험의 작은 그룹을 찾는 것.


Collecting Preferences

  - 선호도 조사 



Finding Similar Users

  - 유사함을 찾는 방법

    + Euclidean distance

       > 유클리드 거리(Euclidean distance)는 두 점 사이의 거리를 계산할 때 흔히 쓰는 방법이다. (참조1)

          2차원적인 거리이다. 그 사이의 변수는 고려되지 않았다. 

          방향성이 무시된다. 

          전체의 평균

          * 두 점 사이의 거리가 가까우면 유사하다?

          * 1:n 관계일 때 거리도 적용가능?


       > 차트로 선호도 영역(Preference Space)에 표현 


    + Pearson correlation

       > 피어슨 상관계수(Pearson correlation coefficient) 는 두 변수간의 관련성을 구하기 위해 보편적으로 이용된다. 

         두 변수간 관련성이 높으면 이 두변수를 사용할 수 있다는 것을 의미? -> 다음 단계의 분석?

       > 여러 그룹의 상호 관계가 있는 일직선을 그린다. 완벽한 상호관계값은 1이다. 


   + Jaccard & Manhatton Distance

       >  자카드는 0~1 


    + best-fit, over-fit, under-fit

       > over-fit : 모든 데이터를 연결해서 적정 추정치를 알 수 없다. 

       > under-fit : 판단 기준이 애매한 것

       > best-fit : 데이터 사이의 측정 구간이 존재하고 그안에 선이 그려짐 



Similarity Metric

  - similarity parameter 가 필요 

  - Jaccard coefficient or  Manhattan distance 을 사용 

  - 거리공간 측정공식




'AI Deep Learning' 카테고리의 다른 글

[ML] 7주차 - 6장 문서 필터링  (0) 2015.02.07
[ML] 6주차 - 5장 최적화  (0) 2015.01.31
[ML] 4주차 - 군집하기  (0) 2015.01.03
[ML] 3주차 - 추천하기  (0) 2014.12.13
[ML] 1주차 - 시작하기  (0) 2014.11.22
posted by 윤영식

BroadleafThymeleaf이라는 서버 템플릿 엔진을 사용하고 있다. Broadleaf은 Tymeleaf을 상속받아 확장한 <blc:XXX> 태그를 xxxProcessor 클래스에 정의하고 있다. 따라서 템플릿에는 Tymeleaf 태그와 Broadleaf이 정의한 <blc:XXX> 태그가 함께 사용된다. 이에 대해 간략히 알아보고 Twitter Bootstrap을 템플릿에 적용해 보자 




Broadleaf에서 Thymeleaf 역할 


  - Thymeleaf은 레이아웃 템플릿 보다 텍스트 템플릿에 가깝고 객체값을 받아서 화면에 표현해 주는 제어구문들을 가지고 있다.

  - AngularJS의 Directive와 서버 템플릿의 Taglib로 사용자 정의한 태그와 백앤드/프론트앤드만 틀리고 유사하다고 하겠다. 

  - 그럼 데이터는 어떻게 주고 받아서 표현할까?

     + Thymeleaf은 HTML을 해석하고 맵핑된 객체를 통해 Value가 설정된 HTML을 최종 클라이언트에 전송한다. 

     + 이때 객체 정보는 Broadlead의 <blc:XXX> 태그에서 Broadleaf core소스에서 정의한 XXXProcessor 가 YYYService를 통해서 Thymleaf에 사용할 객체를 조회/설정/전달한다. 


  - core/broadlleaf-framework : Hibernate와 연결된 DAO와 업무 도메인 Service가 존재한다. 

  - core/broadleaf-framework-web : web이므로 프론트단에 필요한 폼, 필터, 태그처리 프로세스(Processor)등이 존재한다. 

    + DemoSite의 메인 페이지 템플릿은 /site/src/main/webapp/WEB-INF/templates/layout/home.html 해당 파일이다. 

    + home.html을 열어보면 맨위에 하기와 같이 <head>가 설정되어 있다. 

    + <head> 태그를 core/broadleaf-framework-web의 org.broadleafcommerce.core.web.processor.HeadProcessor 가 처리한다.

    + HeadProcessor는 pageTitle 값을 처리하는 클래스이다. 

    + 즉, XxxYyyZzzProcessor 가 있고 태그로 <xxx-yyy-zzz> 태그를 사용하면 XxxYyyZzzProcessor 가 동작하는 것이다. 

// home.html 일부 내역


<head th:include="/layout/partials/head (pageTitle='Broadleaf Demo - Heat Clinic')"></head>

<body>

    <div id="notification_bar"></div>

    <header th:substituteby="layout/partials/header" />

    

    <div id="content" class="width_setter group" role="main">

        <nav th:substituteby="layout/partials/nav" />

        <blc:content contentType="Homepage Banner Ad" />       

        <div id="banners" th:if="${contentItem !=null and contentItem['targetUrl'] != null and contentItem['imageUrl'] != null}">

            <a th:href="@{${contentItem['targetUrl']}}"><img blc:src="@{${contentItem['imageUrl']}}" /></a>       

        </div>

  ... 중략 ...

</body>



// HeadProcessor.java 일부 내역


import org.thymeleaf.processor.element.AbstractFragmentHandlingElementProcessor;

public class HeadProcessor extends AbstractFragmentHandlingElementProcessor {

    @Resource(name = "blHeadProcessorExtensionManager")

    protected HeadProcessorExtensionListener extensionManager;

    public static final String FRAGMENT_ATTR_NAME = StandardFragmentAttrProcessor.ATTR_NAME;

    protected String HEAD_PARTIAL_PATH = "layout/partials/head";


    public HeadProcessor() {

        super("head");

    }


    @Override

    public int getPrecedence() {

        return 10000;

    }


    @Override

    protected boolean getRemoveHostNode(final Arguments arguments, final Element element) {

        return true;

    }


    @Override

    @SuppressWarnings("unchecked")

    protected List<Node> computeFragment(final Arguments arguments, final Element element) {

        String pageTitle = element.getAttributeValue("pageTitle");

        try {

            Expression expression = (Expression) StandardExpressions.getExpressionParser(arguments.getConfiguration())

                    .parseExpression(arguments.getConfiguration(), arguments, pageTitle);

            pageTitle = (String) expression.execute(arguments.getConfiguration(), arguments);

        } catch (TemplateProcessingException e) {}


        ((Map<String, Object>) arguments.getExpressionEvaluationRoot()).put("pageTitle", pageTitle);

      ((Map<String, Object>) arguments.getExpressionEvaluationRoot()).put("additionalCss", element.getAttributeValue("additionalCss"));


        extensionManager.processAttributeValues(arguments, element);

        return new ArrayList<Node>();

    }

}


  - <blc:content> 는 특별히 admin/broadleaf-conentmanagement-modul 에서 org.broadleafcommerce.cms.web.processor.ContentProcessor 로 존재한다.

  - <blc.content> 태그는 내부적으로 서비스를 호출해서 contentItem을 값을 설정해 준다. 이때 contentType="Homepage Banner Ad"는 admin 페이지에서 설정해주는 것이다. 즉, 관리 도구를 통해 Content Mangement를 할 수 있고 이를 간단히 <blc:xxx> 태그를 사용한다.

1) admin 프로젝트에서 ant task중 jetty-demo 실행

2) http://localhost:8081/admin (id:admin, password: admin)

3) Content 메뉴의 content items 목록이 나온다. 여기서 "Content Type"으로 찾으면 됨 



  - Thymeleaf의 특정 인터페이스를 상속받으면 자신만의 태그를 쉽게 만들수 있고 Broadleaf에서는 XXXProcessor로 만들고 있는 것이다. 그리고 <blc:xxx> 태그를 만들어 xxxProcessor내부에서 Service를 통해 Hibernate를 호출해 업무적인 부분을 처리하고 있다.


  얼핏 보면 AngularJS의 Directive를 만들고 내부에서 AngularJS 서비스를 DI(Dependency Injection) 받아 호출하고 서비스내에서 서버로 AJAX 호출하는 계층을 두는 것과 유사하다. 따라서 Broadleaf에서 정의한 xxxProcessor들을 AngularJS Directive로 전환하면 AngularJS기반의 SPA(Single Page Application)으로의 전환이 가능하다. 




Twitter Bootstrap 적용하기 


  - 트위터 부트스트랩은 UI Framework으로 RWD (Responsible Web Design)을 적용할 수 있는 CSS를 제공하고 많이 사용하는 jQuery 플러그인도 함께 제공된다. 

  - 우선 트위터 부트스트랩 v3.3.1을 다운로드하고 압축을 풀면 css, fonts, js 폴더가 있다 

  - site/src/main/webapp 밑에 css, fonts, js를 복사한다. 

  - site/src/main/webapp/WEB-INF/templates/layout 폴더가 상/하/메인에 대한 레이아웃을 설정하는 템플릿 HTML이 존재한다

  - 상단 head.html에 bootstrap.css를 추가하고 하단 footer.html에 bootstrap.js를 하기와 같이 추가한다 

// layout/partials/head.html 


    <blc:bundle name="style.css" 

                mapping-prefix="/css/"

                files="bootstrap.css,

                       style.css,

                       jquery.rating.css" />



// layout/partials/footer.html


    <blc:bundle name="lib.js" 

                mapping-prefix="/js/"

                files="plugins.js,

                       libs/jquery.MetaData.js,

                       libs/jquery.rating.pack.js,

                       libs/jquery.dotdotdot-1.5.1.js,

                       bootstrap.js" />


  - 기존의 CSS는 전부 무시하고 트위터 부트스트랩을 재적용하는 단계이다. 따라서 DemoSite에 적용한 css/style.css 의 내용을 전부 제거 한다.

  - 제거한 내용에 몇가지 CSS를 하기와 같이 적용한다.

/************************************/

/* Header Customizing               */

/************************************/

.navbar .navbar-top {

height: 30px;

padding-top: 5px;

background-color: #F5F5F5;

transition: all 0.1s ease-out 0s;

-webkit-transition: all 0.1s ease-out 0s;

-moz-transition: all 0.1s ease-out 0s;

-ms-transition: all 0.1s ease-out 0s;

-o-transition: all 0.1s ease-out 0s;

font-size: 11px;

line-height: 11px;

text-transform: uppercase;

}


.navbar .container-fluid {

background-color:#525252;

}


.navbar-inverse .navbar-nav > li > a, .navbar-inverse .navbar-brand {

color: #FEFEFE;

}


html, body {

height: 100%;

}


  - site의 WEB-INF/templates/layout/home.html 의 내역에서 필요없는 부분을 주석처리 하고 partials/nav.html 를 사용한다. 

    + <blc:xxx> 로 사용하는 부분을 전부 제거했다. 나중에 필요한 부분에 넣을 것이다. 

    + partails/nav.html 에서 메뉴역할을 하도록 partails/header.html을 nav.html에 통합할 것이다. 

    + <blc:form> 을 통해 제품 검색을 수행한다. 

<head th:include="/layout/partials/head (pageTitle='Broadleaf And Twitter Bootstrap')"></head>


<body>

    <div id="notification_bar"></div>

    

    <nav th:substituteby="layout/partials/nav" />

    

    <footer th:substituteby="layout/partials/footer" />

    

</body>

</html>


  - 다음으로 메뉴를 nav.html에 적용한다. 

    + 트위터 부트스트랩에 맞게 RWD를 적용하고 카테고리(Categories)에 대해 Thymeleaf의 <li th:each> 구문을 적용한다.

    + Admin 화면 (http://localhost:8081/admin) 에서 Category에 해당하는 내용이 메뉴에 적용되는 것으로 broadleaf-framework-web 프로젝트의 org.broadleafcommerce.core.web.processor.CategoriesProcessor가 처리한다. 

<nav>   

    <div th:remove="all">

        <!--

             This template displays the navigation of the site by looking up the category named "Nav"

             and building a list of the categories sub-categories.                          

        -->

    </div>

    

    <blc:categories resultVar="navCategories" parentCategory="Primary Nav" maxResults="6" />

    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">

    

      <!-- TOP Header  -->

      <div class="navbar-top">

      <div class="container">

      <div class="pull-right">

   

    <div th:if="${customer.anonymous}"  th:remove="tag">

            <a th:href="@{/login}">

                <span th:text="#{home.login}">Login</span>

            </a>

            &nbsp;|&nbsp; 

            <a th:href="@{/register}">

                <span th:text="#{home.register}">Register</span>

            </a>

            &nbsp;|&nbsp; 

        </div>

        <div th:unless="${customer.anonymous}" th:remove="tag">

            <span><span th:text="#{home.welcome}">Welcome</span>, <a th:href="@{/account}" th:text="${customer.firstName}"></a></span>

            &nbsp;|&nbsp; 

            <a th:href="@{/logout}">

                <span th:text="#{home.logout}">Logout</span>

            </a>

            &nbsp;|&nbsp; 

        </div>

        <img blc:src="@{/img/icon-cart.jpg}" alt="Shopping Cart Icon" />&nbsp; 

        <a id="cartLink" th:href="@{/cart}">

            <span id="headerCartItemWordSingular_i18n" style="display: none;" th:text="#{home.item}" />

            <span id="headerCartItemWordPlural_i18n" style="display: none;" th:text="#{home.items}" />

            <span class="headerCartItemsCount" th:text="${cart.itemCount}" />

            <span class="headerCartItemsCountWord" th:text="${cart.itemCount == 1} ? #{home.item} :  #{home.items}" />

        </a>

   

    </div>   

    </div>

      </div>

      

      <!-- Responsible Menu -->

      <div class="container-fluid">

        <div class="navbar-header">

          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">

            <span class="sr-only">Toggle navigation</span>

            <span class="icon-bar"></span>

            <span class="icon-bar"></span>

            <span class="icon-bar"></span>

          </button>

          <a class="navbar-brand" href="/">eCommerce</a>

        </div>

        

        <div id="navbar" class="navbar-collapse collapse">

          <!-- Categories -->

          <ul class="nav navbar-nav navbar-right">

       

        <blc:form class="navbar-form navbar-right" style="margin-left:5px; margin-right:5px" th:action="@{/search}" method="GET">

            <input type="search" class="form-control" placeholder="SEARCH PROD" name="q" th:value="${originalQuery}" />

            <input type="submit" class="btn btn-default" value="go" />

    </blc:form>

   

            <li th:each="category : ${navCategories}" th:unless="${#strings.isEmpty(category.url)}">

            <a class="home" th:href="@{${category.url}}" th:class="${categoryStat.first}? 'home'" th:text="${category.name}"></a>

        </li>

          </ul>

        </div>

      </div>

      

    </nav>

    

</nav>


결과 화면은 다음과 같이 정상적인 화면과 RWD 메뉴가 적용된 화면이다. 



* 소스는 제공되지 않습니다. 관심있으신 분은 별도로 문의해 주세요. 



참조 


  - http://www.broadleafcommerce.org

  - Broadleaf core 깃헙 소스

  - http://www.thymeleaf.org

  - 트위터 부트스트랩

posted by 윤영식

BroadLeaf eCommerce 솔루션은 서버는 자바 Spring Framework와 Hibernate를 사용하고 상품에 대한 검색은 Solr를 사용한다. 그리고 클라이언트는 ThymeLeaf 템플릿 엔진을 사용해서 BroadLeaf과 강하게 결합해서 사용된다. BroadLeaf 데모 사이트를 실제 사용할 수 있는 eCommerce 사이트로 전환하는 과정을 살펴본다. 또한 Frontend 쪽에 Twitter BootstrapAngularJS를 적용해 Tymeleaf과 상호 운용될 수 있도록 설정해 본다.






Broadleaf DemoSite 설치 


  - BroadleafCommerce 는 코어 소스이고 Community 버전으로 오픈소스를 제공한다. 

  - BroadleafCommerce 코어 소스를 사용한 DemoSite를 제공한다. 

  - DemoSite를 깃헙에서 받아 사용해도 되고 eclipse workspace 파일을 별도로 이곳에서 받아도 된다. (다운로드 버전은 3.1.8 버전)

    + 만일 3.1.9 버전을 사용하고 싶다면 깃헙의 DemoSite 릴리즈에서 3.1.9-GA를 다운로드하면 된다.


  - DemoSite를 maven project로 eclipse에 import하는 과정은 BroadLeaf Starting 가이드를 참조한다.

    + eclipse는 luna를 사용하면 eclipse용 maven 플러그인이 기본 설치되어 있다. 

    + 단, Apache Maven 은 다운로드해서 설치하고 path를 잡아준다.

    + 최초 DemoSite/build.xml 을 Ant view에서 열고 "change-identifier"를 수행하고

       maven의 grouId를 com.xxxx 식으로 넣고  "y"를 선택하면 자바 패키지와 maven groupId등을 설정한 값으로 자동 변경한다. 


  - 최초에 메이븐 빌드를 한번 해준다. 먼저 DemoSite로 이동해서 하기 명령을 한번 수행한다

$ cd DemoSite

$ mvn clean install


  - Broadleaf은 Site와 Admin으로 구분되어 Site는 쇼핑사이트를 Admin은 카랄로그와 컨텐츠를 관리하고 각각 8080, 8081를 사용한다.

    + site/build.xml 과 admin/build.xml 을 ant view에서 열고 "jetty-demo"를 수행하면 된다. 

    + 데이터베이스는 기본으로 메모리DB인 HSQLDB를 사용한다.

Site

http://localhost:8080


Admin (id: admin, password: admin)

http://localhost:8081/admin/




MySQL전환하기 


  - MySQL 전환작업은 가이드를 참조한다. 

  - mysql로 전환하기 위해 데이터베이스와 계정을 broadleaf 로 지정하고 계정 암호는 abc1234 로 생성한다.

-- %> mysql --user=root -p mysql

-- Enter password: ******


-- mysql> grant all on broadleaf.* to broadleaf@localhost identified by 'abc1234' with grant option;

-- mysql> create database broadleaf;

-- mysql> flush privileges;


-- %> mysql -u broadleaf -p broadleaf

-- Enter password: ******


-- mysql> show grants for broadleaf@localhost;

-- mysql> select current_user;


  - admin과 site가 mysql을 사용하도록 DemoSite/pom.xml과 admin/pom.xml과 site/pom.xml에 다음을 설정한다 

// DemoSite/pom.xml  안에 설정 

<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

    <version>5.1.34</version>

    <type>jar</type>

    <scope>compile</scope>

</dependency> 


// admin, site/pom.xml 안에 설정 

<dependency>

    <groupId>mysql</groupId>

    <artifactId>mysql-connector-java</artifactId>

</dependency> 


  - jetty를 통해 기동될 때 데이터베이스 커넥션 유형을 3가지를 사용하는데 HSQLDB에서 MySQL로 환경값을 바꾸어 주어야 한다. 

    + /site/src/main/webapp/WEB-INF/jetty-env.xml

    + /admin/src/main/webapp/WEB-INF/jetty-env.xml

<New id="webDS" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>jdbc/web</Arg>

    <Arg>

        <New class="org.apache.commons.dbcp.BasicDataSource">

            <Set name="driverClassName">com.mysql.jdbc.Driver</Set>

            <Set name="url">jdbc:mysql://localhost:3306/broadleaf?useUnicode=true&amp;characterEncoding=utf8</Set>

            <Set name="username">broadleaf</Set>

            <Set name="password">abc1234</Set>

        </New>

    </Arg>

</New>

<New id="webSecureDS" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>jdbc/secure</Arg>

    <Arg>

        <New class="org.apache.commons.dbcp.BasicDataSource">

            <Set name="driverClassName">com.mysql.jdbc.Driver</Set>

            <Set name="url">jdbc:mysql://localhost:3306/broadleaf?useUnicode=true&amp;characterEncoding=utf8</Set>

            <Set name="username">broadleaf</Set>

            <Set name="password">abc1234</Set>

        </New>

    </Arg>

</New>

<New id="webStorageDS" class="org.eclipse.jetty.plus.jndi.Resource">

    <Arg>jdbc/storage</Arg>

    <Arg>

        <New class="org.apache.commons.dbcp.BasicDataSource">

            <Set name="driverClassName">com.mysql.jdbc.Driver</Set>

            <Set name="url">jdbc:mysql://localhost:3306/broadleaf?useUnicode=true&amp;characterEncoding=utf8</Set>

            <Set name="username">broadleaf</Set>

            <Set name="password">abc1234</Set>

        </New>

    </Arg>

</New>


  - 하이버네이트의 Dialect를 HSQLDB에서 MySQL로 바꾼다. 

     + /core/src/main/resources/runtime-properties/common-shared.properties  의 맨 하단에 다음을 넣는다. 

# overriding dialect 

blPU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blSecurePU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blCMSStorage.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect


  - DemoSite의 build.properties의 기본 환경값을 HSQLDB에서 MySQL로 바꾼다. 

    + /DemoSite/build.properties 의 맨 하단에 다음을 넣는다. 

# new overriding 

ant.hibernate.sql.ddl.dialect=org.hibernate.dialect.MySQL5InnoDBDialect


ant.blPU.url=jdbc:mysql://localhost:3306/broadleaf

ant.blPU.userName=broadleaf

ant.blPU.password=abc1234

ant.blPU.driverClassName=com.mysql.jdbc.Driver


ant.blSecurePU.url=jdbc:mysql://localhost:3306/broadleaf

ant.blSecurePU.userName=broadleaf

ant.blSecurePU.password=abc1234

ant.blSecurePU.driverClassName=com.mysql.jdbc.Driver


ant.blCMSStorage.url=jdbc:mysql://localhost:3306/broadleaf

ant.blCMSStorage.userName=broadleaf

ant.blCMSStorage.password=abc1234


  - 그리고 가장 중요한 설정은 site와 admin 의 common.properties에 맨 하단에 다음 사항을 필히 넣어 주어야 BLC_SKU 테이블이 생성됨

    + /site/src/main/resources/runtime-properties/common.properties

    + /admin/src/main/resources/runtime-properties/common.properties

# overriding dialect 

blPU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blSecurePU.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

blCMSStorage.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect


  - 전환 후에는 ant task에서 "build-app"를 해주고 "jetty-run-no-db"를 선택하면 build한 target 디렉토리의 소스가 적용된다. 


     




참조 

  

  - Broadleaf v3.1 Guide

posted by 윤영식
2014. 11. 27. 17:37 Languages/Go

스위프트 심화과정을 진행해 보자. 기본 문법을 배웠다면 프로젝트를 생성하고 이제 iOS 앱을 만들어 본다. 물론 앱개발시 기본 언어는 Object-C가 아니라 Swift이다. 




프로토콜


  - 특정 임무나 기능의 일부에 적합하도록 하기 위한 목적으로 작성된 메소드, 속성 등 요구사항에 대한 설계

  - 인터페이스 : 속성 변수와 메소드 포함, 대부분이 인터페이스를 통해 다형성을 보장하는 방식으로 프로그래밍함 

  - 클래스에서 구현 

protocol <pName> {

    func <fName>() {

    }

}


// 예

protocol Sample {

    func execute(name: String) -> String

}


class SampleImpl : Sample {

    func execute(name: String) -> String {

        return "hi \(name)"

    }

}


var s = SampleImpl()

s.execute("Peter")


  - 여러 인터페이스 구현은 콤마(,)로 구분함 




익스텐션 (Extension)


  - 자바스크립트에서 prototype을 통한 객체 자체의 메소드 확장기능과 유사함 

  - 가급적 최상위 클래스 변경은 하지 말자

extension <eName> {

   <확장 대상>

}


// 예

protocol NamedProtocol {

}


extension Int : NamedProtocol {

    var description : String {

        return "current value is \(self)"

    }

    

    func desc() -> String {

        return "current value is \(self)"

    }

    

    func getFirstName(name: String) -> String {

        return "\(self) name \(name)"

    }

}


7.description

7.desc()

7.getFirstName("dowon")




앱 프레임워크


  - 스토리 보드

    + 안드로이드의 XML 환경 설정과 유사함. 대신 비쥬얼하게 인터렉티브 UI 디자인이 가능하다 

  - iOS 4계층 프레임워크 

    + Core OS -> Core Services -> Media -> Cocoa Touch

    + Cocoa Touch : 파운데이션 (Foundation), UIKit 등이 포함,  접두어 : NS - 파운데이션, UI - UIKit

    + Core Services : 코어 파운데이션

  - Cocoa Framework 

    + 맥북의 애플리케이션 개발

    + Cocoa Touch F/W은 iOS 앱 개발 

    + 80% 가량이 Cocoa F/W 과 Cocoa Touch F/W 이 겹친다. 

  - Cocoa Touch F/W = Foundation F/W (NS*) + UIKit F/W (UI*)




스플래시


  - 최초에 뜨는 스플래시 화면 제어하기 

  - AppDelegate.swift 파일이 앱의 LifeCycle을 관리한다?

  - LaunchScreen.xib를 추가할 수 있다. => 프로젝트 Deployment Info의 Main Interface에서 최초 페이지를 선택할 수 있다. 




네비케이션 뷰 컨트롤러 


  - 뷰를 스택으로 관리한다

  - 기본이 되는 Root View Controller가 있다

  - push 하면 스택에 쌓여 위에 노출되고, pop 하면 화면이 제거됨 : pushViewController

  - 상단 메뉴 : Editor -> Embed in -> Navigation Controller를 추가한다 

class NextView : UIViewController {

    

    func nextView(ctrlName: String, transition: UIModalTransitionStyle) {

        // 두번째 화면의 인스턴스를 만든다

        var uvc: UIViewController = self.storyboard?.instantiateViewControllerWithIdentifier(ctrlName) as UIViewController

        

        // 화면 전환 스타일을 지정한다

        uvc.modalTransitionStyle = transition

        

        // 화면을 호출한다

        //self.presentViewController(uvc, animated: true, completion: nil)

        self.navigationController?.pushViewController(uvc, animated: true)

    }

    

    func dismissView() {

        //self.presentingViewController?.dismissViewControllerAnimated(true, completion: nil)

        self.navigationController?.popViewControllerAnimated(true)

    }

}




세그 (Segue)


  - 화면 연결 처리 전용 객체 

  - Source : 자신이 있는 곳

  - Destination : 목적지 

  - 연결 방법

    + 첫번째 화면(Source) 버튼을 Ctrl 누른 상태에서 두번째 화면(Destination)으로 드래그 앤 드롭을 하면 Segue 연결 팝업창이 나옴

    + 두번째 화면을 선택하고 오른쪽 상단의 마지막 아이콘 (->) 을 선택하고 Presenting Segues 에서 Present modally를 선택하고 첫번째 화면으로 드래그 앤 드롭해 연결

  - 값 전달하기 

    + 직접 전달 : 두번째 화면 컨트롤러로 캐스팅

    + segue를 연결해서 전달 : prepareForSegue 재정의 내역에 segue. destinationViewController를 두번째 화면 컨트롤러로 캐스팅

// 첫번째 화면 컨트롤러 

class FirstViewController : UIViewController {

    

    // source 화면에서 버튼을 추가하고 destination 화면으로 이동할 때 값을 전달하는 방법 

    @IBAction func nextPresentation(sender: AnyObject) {

        var uvc : SecondViewController = self.storyboard?.instantiateViewControllerWithIdentifier("secondViewController") as SecondViewController

        

        uvc.param = "Direct Parameter"

        

        self.presentViewController(uvc, animated: true, completion: nil)

    }

    

    // segue로 연결해서 값을 전달하는 경우 

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

        var uvc : SecondViewController = segue.destinationViewController as SecondViewController

        

        uvc.param = "Segue Parameter"

    }

}


// 두번째 화면 컨트롤러 

class SecondViewController : UIViewController {

    

    var param : String = ""

    

    override func viewDidLoad() {

        NSLog("Excute Second View Loaded value is %@", param)

    }

}


  - 세그를 커스터마이징할 수 있다. : 이동 시간, 이동 효과등을 설정할 수 있다

    + 스토리 보드에서 custom segue를 선택하고 CustomSegue를 선택

import UIKit


// 반드시 상속 

class CustomSegue : UIStoryboardSegue {

    // 반드시 구현 

    override func perform() {

        let src = self.sourceViewController as UIViewController

        let dest = self.destinationViewController as UIViewController

        

        UIView.transitionFromView(src.view, toView: dest.view, duration: 1.0, options: UIViewAnimationOptions.TransitionCurlDown, completion: nil)

    }

}




접두어 


  - NS : 파운데이션 

  - CF : Core 파운데이션 

  - IB : @IBOutlet 같은 어노테이션이 컨트롤러에 있으면 스토리보드에서 자동 인식하는 것이다. 




UIAlertView


  - iOS 메세지 전달은 델리게이트 패턴을 쓴다 

  - 이벤트 처리 담당자가 따로 있어서 발생시 현재 떠 있는 창에 알려주는 구조 

  - UIAlertViewDelegate 프로토콜(protocol)을 구현하면 Alert View Controller를 제어할 수 있다



참조 


  - 옵셔널 체인 : 코드에서 ? 사용하기

'Languages > Go' 카테고리의 다른 글

[Swift] 스위프트 배우기 - 1일차  (0) 2014.11.26
posted by 윤영식
2014. 11. 26. 12:30 Languages/Go

애플의 새로운 언어인 스위프트(Swift)를 배워보자. 



배경


  - 안드로이드에 빼앗긴 시장을 다시 탈환하기 위한 새로운 언어 

  - Object-C의 굴레에서 벗어나 누구나 쉽게 접근할 수 있게 하고 싶다. 

  - 2014년 6월 2일 Apple WWDC 발표이후 2014년 11월까지 문법의 20%까지 바뀌었다. (Swift GM 정식 버전이 나옴)

  - 레퍼런스 북을 보자 




개념


  - Fast 빠르다 : LLVM 컴파일러 코드 분석기를 이용하여 컴파일과 최적화를 수행

  - Cocoa Framework 접근 : Mac - Cocoa Framework, iOS - Cocoa Touch Framework 접근 가능

  - Safe 안전하다

    + 자료형 자동 추론 및 안정성 증가 : try~catch 구문이 없다 

    + 포인터에 대한 직접 접근 제한

    + ARC(Automatic Reference Counting)를 사용한 메모리 관리 자동화 (OS X 10.7, IOS 5 버전 이상부터 ARC full feature 사용가능)

  - Modern

   + 파이썬 언어에 기반한 읽고 쓰기 쉬운 문법

   + 디버깅, 유지보스에 쉬운 코드 사용 (코코아 펑션은 옆으로 너무 길다)

  - Interactive

   + Xcode 6 의 playground에서 코드 작성하면서 결과 확인이 가능 

  - Unified

   + Swift <-> Object-C 간의 연계 가능 




문법 특징 


  - 컴파일언어가 아닌 스크립트 언어

  - 데이터 타입에 대한 구분이 엄격 : 변수, 상수 선언시 타입입이 결정

  - 엔트리 포인트가 없음 (Java의 main 같은 것이 없다)

  - 세미 콜론이 필요없음 (붙여도 무방)

  - 변수의 시작은 소문자, 클래스의 시작은 대문자로 하자 (대소문자 구분)

  - 문자 하나던 문자열든 더블 쿼팅 (이중 따옴표)를 사용한다

  - import를 사용해 라이브러리를 호출 (Node.js의 require와 유사)




Playground


  - Swift 언어 전용의 프로토타입용 코드 작성툴

  - 처리결과의 stack 확인 가능 (코딩 영역과 스택 영역 존재)




문법


  - 변수 선언 var, 상수 선언 let (상수 변경 불가 및 선언과 동시 초기화)

var addr = "과천시"

var zip : String

zip = "040-234"


let name = "Peter Yun"


단, 클래스의 인터턴스 상수일 경우 선언과 초기화 분리가능 

class ConstTest {

   let name : String = "hi"

}

   또는 

class ConstTest {

    let name : String

    init() {

        name = "Peter"

    }

}


  - 이름은 대소문자 구분, 첫자 숫자 안됨

  - 변수, 상수던 초기화 값에 따라 타입이 결정됨 (타입 추론 : Type Infer)

  - 선언과 초기화가 분리 될때는 타입 선언이 필요 (타입 어노테이션 : Type Annotation)

var name = "Peter"


// 타입 어노테이션

// var 변수명 : 데이터 타입

// 또는

// var 변수명 : 테이터 타입 = 값

var addr : String

addr = "Korea Seoul"


  - 타입 : Int, UInt / Float, Double / String(문자열형) / Character(문자형) / Bool

// 문자열형을 문자형으로 출력 

let str = "This is type"

for char in str {

    println(char)

}


  - "\(변수 또는 상수명)" 문자열에 포함 가능 및 expression 연산 가능  

let name = "Peter"

let str = "Hi \(name)"


// expression

let birthYear = 1980

let nowYear = 2014

let age = "My age is \(nowYear - birthYear + 1)"


let str02 = "1+2+3 = \(1+2+3)"


  - 단항, 이항, 비교, 논리 연산자 

// != 양쪽 띄워쓰기 안하면 오류 발생

var a = 20

var b = 30

println(a!=b)


  - 닫힌 범위 연산자 (Closed range operator) :  세개 점으로 표현  예) 1...5    (1,2,3,4,5)

  - 반닫힘 범위 연산자 (Half-closed range operator) :  두개 점과 <로 표현 예) 1..<5  (1,2,3,4), 배열 순회시 사용함 

let a=1

let b=5


for row in a...b {

    println(row)

}


for row in a..<b {

    println(row)

}


  - 집합 자료형 : 다수 개의 관련된 데이터를 묶음으로 관리할 수 있는 자료형

    + 배열 : Array

    + 튜플

    + 딕셔너리 : Dictionary




배열 


  - 배열 순회

var peter = ["hi", "peter", "yun"]

peter.append("Korea")


for(var i=0 ; i<peter.count ; i++) {

    println("\(i) 번째 \(peter[i]) 이것이다." )

}


for i in 0..<peter.count {

    println("\(i) 번째 \(peter[i]) 이것이다." )

}


for row in peter {

    println("element \(row) 입니다.")

}


  - 배열 선언 및 초기화 

    + Array<> 제너릭(Generic)을 사용함 

    + insert, append를 통해 확장함 

    + Array(count: 10, repeatedValue : "default") 형식으로 인덱스 개수 확보 

// 선언 

var 배열변수명 : Array<배열원소타입>

var 배열변수명 : [배열원소타입]


// 초기화 

var 배열변수명 = Array<배열원소타입>()

var 배열변수명 = [배열원소타입]()


// 선언 + 초기화 

var 배열변수명 : Array<배열원소타입> = Array<배열원소타입>()

var 배열변수명 : [배열원소타입] = [배열원소타입]()


// 예) 

var m : Array<String>

m = Array()


m.append("hi")

m.append("Peter")

m[2] = "zzz"  // error : 인덱스가 확보되지 않았기 때문 

println(m)


var n = [String]()

n.append("hi")

n.append("pp")

println(n)


var c = Array(count: 10, repeatedValue: "dd")

c[0] = "hi"

c[1] = "peter"

c[9] = "zzz"

println(c)


  - Array : 스위프트 자료형, NSArray/NSMutableArray : 파운데이션 프레임워크 자료형 




튜플


  - 집합 자료형 : 순서가 존재하지 않으며 (for 구문 순회할 수 없다는 의미), 이형 데이터를 모두 저장할 수 있는 집합 자료형 

  - () 기호속에 나열해 정의한다 예) ("A", 3, 15.5, true)

var tuple = ("hi", "peter", 35, true)


tuple.0

tuple.1

tuple.2

tuple.3


let (a, b, c, d) = tuple


  - 튜플은 함수에서 많이 사용한다 

func getT() -> (String, String, Bool) {

    return ("hi", "peter", true)

}


  - 딕셔너리 : 키/값을 사용

let cap = ["kr":"seoul", "us":"washington"]


cap["kr"]!  / "seoul"

cap["kr"]   / {Some "seoul"}


또는 


var cap2 : Dictionary<String, String>

cap2 = ["kr":"seoul", "us":"washington"]


cap["kr"]!

cap["kr"]


또는 


var cap3 : [String: String]

cap3 = ["kr":"seoul", "us":"washington"]


cap3["kr"]!

cap3["kr"]


  - 딕셔너리는 순회할 수 있다. 단, 순회시에 튜플 형태로 순회한다. 

for row in cap3 {

    let (key, value) = row

    println("\(key) = \(value)")

}


또는 


for (key, value) in cap3 {

    println("\(key) = \(value)")

}


  - 딕셔너리 값 수정 : updateValue:forKey

cap3.updateValue("SEOUL", forKey: "kr")   // 값 Optional("seoul") 반환 


cap3["kr"]!


  - ! 느낌표의 의미 : 옵셔널,  Optional("seoul") 을 "seoul" 로 변환 - 딕셔너리의 참조 




옵셔널 


  - 오류가 발생할 가능성이 있는 값 예) "hi".toInt() 일때 에러가 있을만한 것은 Optional로 랩핑해서 반환함

    + 모든 것에 대해 랩핑해 버림 

    + Optional()

"123".toInt()  ==> {Some 123}


  - 옵셔널 만들기 : 선언시 타입뒤에 ? 를 붙이면 Optional로 랩핑하여 반환함 

    + nil 이거나 정상값 

    + 느낌표 ! 는 옵션널 랩핑된 것을 벗겨내고 값을 표현할 때  사용한다 (옵셔널 강제 해제)

    + 딕셔너리의 경우 cap["key"] 의 경우 값이 nil일 수 있으므로 Optional 처리가 자동처리된다. 따라서 값을 얻을 때 cap["kr"]! 를 해줌.

var optInt : Int? 

var optStr : String?


var optStr : String?    ===> nil

optStr = "hi"              ===> {Some "hi"}


println(optStr)           ===> Optional("hi")

println(optStr!)          ===> "hi"


  - 문자의 경우 ! 사용전에 nil 체크를 해준다 

if optStr != nil {

    optStr!

}




함수 


  - func 키워드 사용

func 함수명 (인자명:타입, 인자명:타입 ... ) -> 반환_타입 {

    실행 내용

    return 반환값 

}




클래스와 구조체


  - Cocoa Touch Framework를 통해 가장 많이 사용하는 것임 

  - class, struct 둘다 첫 문자는 대문자

  - class, struct 둘다 속성 접근은 . (점) 사용 

class CName {

  statemment

}


// 인스턴스화 

var c = CName()


struct SName {

  statement

}


// 인스턴스화 

var s = SName()


  - 클래스 만의 특징

    + 상속이 가능 

    + 타입 캐스팅이 가능 

    + 디시리얼라이즈 통해 자원 해제 가능 

    + 참조 카운팅을 통해 클래스 인스턴스에 하나 이상의 참조 가능 

  - 타입 메서드 : 클래스 소속 메소드  

class Sample {

    func getInstance() -> Int {

        return 50

    }

    class func getClass() -> Int {

        return 100

    }

}


Sample.getClass()

Sample.getInstance()  // 에러 

var s = Sample()

s.getInstance()


  - init() 클래스의 생성자, 상속, override (재정의. 단, 중복정의는 안됨)

class NamedShape {

    var numberOfSides : Int = 0

    var name: String

    

    // 생성자 

    init(name:String) {

        self.name = name

    }

    

    func simpleDescription() -> String {

        return "A shape \(numberOfSides)"

    }

}


// 상속 

class Square: NamedShape {

    var sideLength: Double

    

    init(sideLength: Double, name: String) {

        self.sideLength = sideLength

        // 부모 생성자 호출 

        super.init(name: name)

        numberOfSides = 4

    }

    

    func area() -> Double {

        return sideLength * sideLength

    }

    

    // 재정의의

    override func simpleDescription() -> String {

        return "A square with sides of length \(sideLength)"

    }

}


// 인스턴스 사용 

let test = Square(sideLength: 5.2, name: "hi dowon")

test.area()

test.simpleDescription()

test.name




UIKit Framework 


  - 앱을 만들기 위해 반드시 사용하는 프레임워크 

  - NSObject 상속




참조 


  - ARC wikipedia


'Languages > Go' 카테고리의 다른 글

[Swift] 스위프트 배우기 - 2일차  (0) 2014.11.27
posted by 윤영식
2014. 11. 22. 11:36 AI Deep Learning

  비오는 토요일 오전 강남 토즈타워에서 다섯분과 함께 머신 러닝 스터디를 시작한다. 

  모임 : https://www.facebook.com/groups/1511952519075217/  

  참여자 : 봉성주님, 서병선님, 김민기님, 이웅재님과 함께 한다. 

  기타 : 총 12주동안 http://www.it-ebooks.info/book/330/ 책을 1 챕터식 읽고 질문하고 답하기. 


  책의 서문에 나온 내용이다. 인터넷을 기반으로 하는 집단 지성 데이터를 수집하여 다양한 분야를 들여다 보는데 책의 목적이 있는 것 같다. 

 It covers ways to get hold of interesting datasets from many web sites you’ve probably heard of, ideas on how to collect data from users of your own applications, and many different ways to analyze and understand the data once you’ve found it.




1장 


  실제 생활에서 집단 지성은 어디에서 쓰는 것일까 예를 들어준다. 

  - 시장 예측

  - 금융 사기 탐지

  - 머신 비젼

  - 공급망 최적화

  - 주식 마켓 분석

  - 국가 안보 


  머신러닝

  - 클렌징이 중요하다. 

    + 클렌징은 누가 하는가? 데이터 마이닝

  - 이미 되어 있다고 가정하고 머신러닝을 수행한다. 

  

  


회고 


  하고 싶었던 것을 함께 할 수 있어서 좋다. 책이 나의 목적과 너무 잘 맞는다. 피부에 와 닿는 것을 경험할 수 있을 것 같다. 나에겐 신선한다. 




커뮤니케이션 방식 


  - slack 

  - github 저장소 : https://github.com/ML-Lounge/Collective-Intelligence

'AI Deep Learning' 카테고리의 다른 글

[ML] 7주차 - 6장 문서 필터링  (0) 2015.02.07
[ML] 6주차 - 5장 최적화  (0) 2015.01.31
[ML] 4주차 - 군집하기  (0) 2015.01.03
[ML] 3주차 - 추천하기  (0) 2014.12.13
[ML] 2주차 - 추천하기  (0) 2014.12.06
posted by 윤영식
2014. 8. 4. 00:41 AngularJS

  AngularJS(이하, 앵귤러) 기반의 싱글 페이지 웹 애플리케이션 개발에 대한 책을 집필하고 있다. 책안에 들어갈 내용을 위해 참조한 내역을 정리해 보고자 한다. 요즘 가장 큰 화두는 다양한 프론트 앤드 프레임워크가 나옴에 따라 프론트 앤드 개발에도 아키텍팅이 필요하다는 것이다. 프론트 앤드에서는 SPA(Single Page Application 이하, 싱글 페이지 웹 애플리케이션)가 앵귤러 프레임워크 기반으로 많이 소개 되고 있다. 싱글 페이지 웹 애플리케이션 접근 방식은 JSP, PHP같은 서버 템플릿이나 스프링 프레임워크에 익숙한 개발자에게는 생소한 개념이다. 


  싱글 페이지 웹 애플리케이션(SPA)은 "싱글 페이지 웹" 글자만 빼면 그냥 애플리케이션이다. 윈도우에 설치해서 사용하는 .exe 애플리케이션 개발 방식과 하등 차이가 없고 보여지는 기반이 브라우저안이라는 것 밖에 없다. 몇년전 리치 인터넷 애플리케이션(RIA)를 이끌었던 플랙스(Flex)를 떠올려도 좋다. 하지만 지금은 모바일과 웹의 시대이니 HTML/CSS/JavaScript 만으로도 충분히 애플리케이션을 만들 수 있어야 한다. 


  앵귤러는 애플리케이션을 만드는 프레임워크이다. 스프링 MVC 패턴의 개발을 했다면 앵귤러에서도 그렇게 할 수 있다. 스프링 의존성 주입의 편리함을 누리고 있다면 앵귤러에서도 그렇게 할 수 있다. 이제 웹의 세상에 맞는 애플리케이션 개발자로 거듭나 보자. 






목차 


  1장. 싱글 페이지 애플리케이션 개발 준비

    + 1-1 개발 도구 준비

    + 1-2 싱글 페이지 애플리케이션 생성

    + 1-3 애플리케이션 컴포넌트 생성

    + 1-4 애플리케이션 테스트 및 빌드빌드



  2장. AngularJS 프레임웍 이해

    + 2-1 MV* 프레임웍

    + 2-2 양방향 데이터 바인딩

    + 2-3 의존성 주입

    + 2-4 클라이언트 템플릿

    + 2-5 지시자 (Directive)

    + 2-6 테스트 프레임웍

    


  3장. 싱글 페이지 애플리케이션 기획 및 생성

    + 3-1 애플리케이션 기획

    + 3-2 애플리케이션 제너레이터 생성

    + 3-3 싱글 페이지 애플리케이션 생성

    + 3-4 단위 업무를 위한 앵귤러 컴포넌트 조합



  4장. 애플리케이션을 위한 공통 프레임웍 개발

    + 4-1 공통 프레임웍 모듈 개발

    + 4-2 로그인 프론트앤드 개발

    + 4-3 OAuth를 이용한 인증 처리

    


  5장. 메인 페이지 개발 

    + 5-1 백앤드 API 개발

    + 5-2 프론트앤드 화면 레이아웃

    + 5-3 그룹 목록 및 정보 표현 



  6장. 그룹 페이지 개발 

    + 6-1 그룹 정보 페이지

    + 6-2 그룹 활동 페이지 

    + 6-3 설문 카드 생성

    + 6-4 설문 카드 목록에 표현

    + 6-5 설문 응답 및 결과 표현



  7장. 실시간 반응 개발

    + 7-1 Socket.IO 기반 실시간 연동

    + 7-2 카드 표현 고도화

    + 7-3 AngularJS 성능 옵션



 총 7개의 목차 중에서 1, 2장을 출판사의 양해를 얻어 공개토록 한다. 

  

posted by 윤영식
2014. 8. 4. 00:11 AngularJS/Concept

Highchart에 대한 Directive를 만들며서 controller, compile, link 등을 써보고 있는데, 성능 최적화 및 실시간 데이터 업데이트 방법등에 대해서 고민하면서 좋은 글이 있어서 머리도 정리할 겸 따라쟁이 해본다. 



1. Directive 사용 영역

  - HTML안에서 element, attribute, class name, comment 4영역

<angular></angular>

<div angular></div>

<div class="angular"></div>

<!-- directive: angular -->



2. 이름 규칙

  - HTML안에서 하이픈(hyphens) 으로 단어 사이를 구분하여 사용

  - JavaScript안에서 단어사이는 대문자로 구분하여 사용

<div the-quick-silver-rider-youngsik></div>


App.directive('theQuickSilverRiderYoungsik', function() { ... });



3. 테스트전 SaaS

  - http://plnkr.co/  코드 테스트 Preview 서비스를 이용한다

  - GitHub 아이디로 로그인 한후 -> [Launch the Editor] 한다

  - 자신의 테스트 코드 및 타인의 코드를 서로 공유할 수 있다

  - 해당 서비스 자체가 AngularJS 기반으로 만들어 졌다 (Node.js + AngularJS 소스 공개)

  - 그림 오른쪽의 angular.js 라이브러리 버전을 선택하면 index.html에 자동 삽입되고 코딩을 시작할 수 있다



4. 간단한 테스트 수행

  - 사용자 정의 태그를 만든다

  - 이름 : angular

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add the created custom 'angular' directive -->
    <angular></angular>
  </body>

</html>


// script.js

var App = angular.module('App', []);
 
App.directive('angular', function() {
  return {
    restrict: 'ECMA',
    link: function(scope, element, attrs) {
      var img = document.createElement('img');
      img.src = 'http://goo.gl/ceZGf';
 
 
      // directives as comment
      if (element[0].nodeType === 8) {
        element.replaceWith(img);
      } else {
        element[0].appendChild(img);           
      }
    }
  };
});


  - plunker preview


  - <angular> 태그에 <img> 태그가 추가되었다



5. Directive Definition

  - AngularJS는 기동될 때(bootstrapped), 사용자정의 및 빌트인된 directives를 찾고 $compile() 메소드를 이용하여 컴파일을 한다

  - compile 메소드 역할 : 모든 directives 요소를 찾아서 우선순위 sort하고 link function을 만든다. 또한 scope와 element사이의 2-way data binding을 위하여 $watch를 셋팅하거나 event listener를 생성된 (ng-app, ng-controller, ng-include, etc)같은 scope에 link한다  

  - Directive 정의

var myModule = angular.module(...);
myModule.directive('directiveName', function (injectables) {
  return {
    restrict: 'A',
    template: '<div></div>',
    templateUrl: 'directive.html',
    replace: false,
    priority: 0,
    transclude: false,
    scope: false,
    terminal: false,
    require: false,
    controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
    compile: function compile(tElement, tAttrs, transclude) {
      return {
        pre: function preLink(scope, iElement, iAttrs, controller) { ... },
        post: function postLink(scope, iElement, iAttrs, controller) { ... }
      }
    },
    link: function postLink(scope, iElement, iAttrs) { ... }
  };
});



5-1. Compile function

  - compile function이 link function을 만든다(produce)

  - 2개 파라미터

    + tElement : directive가 선언되어진 template element (jQuery object이다. 따라서 $로 다시 wrap하지 마라)

    + tAttrs : tElement와 관련된 모든 attributes 목록

  - ng-repeat같은 것을 사용할 경우 성능상의 이슈로 compile function이 사용된다. DOM과 scope객체를 연결지으려는데 데이터를 가져올 때마다 바인드과정을 거치지 않고 최초 한번 바인드되고 link functioin을 통해서 데이터 변경시에 scope-DOM간의 2-way 바인딩을 하여 변경을 반영한다

// in index.html

<div compile-check></div>


// in script.js

App.directive('compileCheck', function() {
   return {
     restrict: 'A',
     compile: function(tElement, tAttrs) {
       tElement.append('Added during compilation phase!');
     }
   };
 });


  - index.html에 <div compile-check></div>를 추가하고 script.js에 코드를 추가하면 하단에 'Added during compilation phase!'가 첨부된다



5-2. Link function

  - DOM과 scope 객체를 2-way data binding 하는 역할이다. compile function에서는 scope 객체에 접근할 수 없다

  - $watch 메소드를 통하여 사용자정의 listener를 생성할 수 있다. (register등록은 angular가 자동으로 해준다)

  - 3개 파라미터

    + element : directive와 바인드된 요소

    + scope : directive에 의해 사용되어지는 scope 객체

    + attrs : 요소와 관련된 모든 attribute목록

 


5-3. Restrict

  - E : elements

  - A : attributes

  - C : class name (CSS)

  - M : comments

  - HTML5 호환 표기가 가능한다 : 빌트인 ng-bind 사용

<span ng:bind="name"></span>
<span ng_bind="name"></span>
<span ng-bind="name"></span>
<span data-ng-bind="name"></span>
<span x-ng-bind="name"></span>



5-4. Template

  - html에 넣은 요소와 교체할 내역

  - html안의 태그 반복되는 부분을 별도의 모듈화로 중복을 방지 할 수 있다 

  - https://api.github.com/repos/angular/angular.js 호출하면 angular.js 관련 정보가 JSON 형태로 나옴

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add controller & whoiam directive -->
    <div ng-controller="DemoCtrl">
      <div whoiam>This text will be overwritten</div>
    </div>
  </body>
 
</html>


// script.js

var App = angular.module('App', []);

App.run(function($rootScope) {
  $rootScope.header = 'I am bound to rootScope';
});
 
App.controller('DemoCtrl', function($scope) {
  $scope.footer = 'I am bound to DemoCtrl';
});
 
App.directive('whoiam', function($http) {
  return {
    restrict: 'A',
    template: '{{header}}<div class="thumbnail" style="width: 80px;"><div><img ng-src="{{data.owner.avatar_url}}"/></div><div class="caption"><p>{{data.name}}</p></div></div>{{footer}}',
    link: function(scope, element, attrs) {
      $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) {
        scope.data = data;
      });
    }
  };
});


  - $scope는 $rootScope를 상속받기 때문에 template에서 {{header}}, {{footer}}를 호출 할 수 있다



5-5. TemplateUrl

  - 템플릿 마크업 및 별도의 html 파일로 관리한다

  - template 파일의 로딩을 빠르게 할려면 메모리에 적제하여 사용한다. $templateCache 

  - <script> 태그를 이용한다

<script type='text/ng-template' id='whoiam.html'></script>


  - inde.html 내역 : template script 태그를 head 태그안에 넣는다. id로 whoiam.html을 사용한다

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
   
    <!-- 3) add the template script tag -->
    <script type='text/ng-template' id='whoiam.html'>
      <div class="thumbnail" style="width: 260px;">
          <div><img ng-src="{{data.owner.avatar_url}}" style="width:100%;"/></div>
          <div class="caption">
            <p><b>Name: </b>{{data.name}}</p>
            <p><b>Homepage: </b>{{data.homepage}}</p>
            <p><b>Watchers: </b>{{data.watchers}}</p>
            <p><b>Forks: </b>{{data.network_count}}</p>
          </div>
        </div>
     </script>
  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 4) add controller & whoiam directive -->
    <div ng-controller="DemoCtrl">
      <div whoiam>This text will be overwritten</div>
    </div>
  </body>
 
</html>


  - script.js 내역 

var App = angular.module('App', []);

App.controller('DemoCtrl', function($scope) { });
 
App.directive('whoiam', function($http) {
  return {
    restrict: 'A',
    templateUrl: 'whoiam.html',
    link: function(scope, element, attrs) {
      $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) {
        scope.data = data;
      });
    }
  };
});


  - 호출한 angular.js 정보가 출력된다



5-6. Replace

  - directive를 설정한 태그를 템플릿 태그로 교체하고자 할때 따라서 template 또는 templateUrl과 함께 사용한다

  - replace: true

  - index.html : elment, attribute, class name, comment 4가지 설정

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive -->
    <div angular></div>
    <div class="angular"></div>
    <angular></angular>
    <!-- directive: angular -->
  </body>
 
</html>


  - script.js 내역

var App = angular.module('App', []);

App.directive('angular', function() {
  return {
    restrict: 'ECMA',
    template: '<img src="http://goo.gl/ceZGf" />',
    replace: true
  };
});


  - 결과 html

// attribute

<img src="http://goo.gl/ceZGf" angular=""></img>


// class name

<img class="angular" src="http://goo.gl/ceZGf"></img>


// element

<img src="http://goo.gl/ceZGf"></img>


// comment

<img src="http://goo.gl/ceZGf" angular=""></img>


  - img 태그가 4개 생성되어서 이미지가 4개 보인다



5-7. Priority

  - 우선순위에 따라서 compile/link의 순위를 정한다. 값이 클 수록 우선순위가 높다

  - 이것은 미리 컴파일된 directive의 결과값을 체크하여 수행할 필요가 있을 때 사용한다

  - zero이면 priority 설정을 하지 않고 default priority를 사용한다

  - bootstrap의 'btn-primary' 클래스를 적용하려고 할때 index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive -->
    <div style='padding:100px;'>
      <div primary btn>The Hitchhiker Guide to the Directive Demo by Dowon</div>
    </div>
  </body>
 
</html>


  - script.js 내역 : 우선순위로 btn이 먼저 생성되었으므로 primary에 대한 적용이 가능해 진다

var App = angular.module('App', []);

App.directive('btn', function($timeout) {
  return {
    restrict: 'A',
    priority: 1,
    link: function(scope, element, attrs) {
      element.addClass('btn');
    }
  };
});
 
App.directive('primary', function($http) {
  return {
    restrict: 'A',
    priority: 0,
    link: function(scope, element, attrs) {
      if (element.hasClass('btn')) {
        element.addClass('btn-primary');
      }
    }
  };
});


  - bootstrap의 btn-primary CSS가 적용된 버튼이 보인다



5-8. Terminal

  - 가장 최근에 수행된 directive에 terminal: true를 설정하면 그 이후 directive는 수행되지 않는다

  - index.html 내역

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive -->
    <div first second></div>
    <ul>
        <li ng-repeat="item in ['one', 'two', 'three']" no-entry>{{item}} </li>
    </ul>
  </body>
 
</html>


  - script.js 내역 : first -> second -> noEntry 가 수행되지만 second에 terminal: true 설정으로 매noEntry는 수행되지 않는다

  - ng-repate, ng-switch는 priority 높음에도 나중에 수행됨. 버그?

var App = angular.module('App', []);

App.directive('first', function() {
  return {
    restrict: 'A',
    priority: 3,
    link: function(scope, element, attrs) {
      element.addClass('btn btn-success').append('First: Executed, ');
    }      
  };
});
 
App.directive('second', function() {
  return {
    restrict: 'A',
    priority: 2,
    terminal: true,
    link: function(scope, element, attrs) {
      element.addClass('btn btn-success').append('Second: Executed ');
    }      
  };
});
 
App.directive('noEntry', function() {
  return {
    restrict: 'A',
    priority: 1000,
    link: function(scope, element, attrs) {
      element.append('No Entry: Executed ');
    }      
  };
});


  - first, second의 priority 값을 서로 바꾸어 보라 : 버튼의 text 순서가 바뀔 것이다. 또는 noEntry의 priority값을 1000이하로 하면 directive가 실행된다



5-9. Controller

  - Directive를 제어를 담당한다.

  - $scope, this 를 사용하여 properties/methods를 바인할 수 있다

  - this 키워드로 바인딩된 데이터는 require옵션을 사용하여 controller를 injecting함으로써 다른 directives에서 엑세스할 수 있게 한다.

  - 5-10의 require에서 예제 진행함

App.directive('powerSwitch', function() {
      return {
        restrict: 'A',
        controller: function($scope, $element, $attrs) {
          $scope.state = 'on';
 
          $scope.toggle = function() {
            $scope.$apply(function() {
              $scope.state = ($scope.state === 'on' ? 'off' : 'on');
            });
          };
 
          this.getState = function() {
            return $scope.state;
          };
        },
     };
});



5-10. Require

  - controller를 다른 directive에 전달해서 compile/linking function안에 연관시킬 수 있다

  - 같은 element 또는 부모와 바인드 되어야 한다

  - prefixed 부호가 붙는다

    + ? : 지정한 directive가 없더라도 에러가 발생시키지 않는다

    + ^ : 부모 element위의 directive를 찾는다. 같은 element위치는 유효하지 않다


  - index.html 내역 

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link href="style.css" rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive : parent -> child depth  -->
    <div class="btn btn-success" power-switch>
      {{'Switched ' + state | uppercase}}
    
      <div lightbulb class='bulb' ng-class="bulb"></div>
    </div>
  </body>
 
</html>


  - script.js 내역

var App = angular.module('App', []);

App.directive('powerSwitch', function() {
  return {
    restrict: 'A',
    controller: function($scope, $element, $attrs) {
      $scope.state = 'on';
 
      $scope.toggle = function() {
        $scope.$apply(function() {
          $scope.state = ($scope.state === 'on' ? 'off' : 'on');
        });
      };
 
      this.getState = function() {
        return $scope.state;
      };
    },
    link: function(scope, element, attrs) {
      element.bind('click', function() {
        scope.toggle();
      });
 
      scope.$watch('state', function(newVal, oldVal) {
        if (newVal === 'off') {
          element.addClass('disabled');
        } else {
          element.removeClass('disabled');
        }
      });
    }
  };
});
 
App.directive('lightbulb', function() {
  return {
    restrict: 'A',
    require: '^powerSwitch',
    link: function(scope, element, attrs, controller) {
      scope.$watch(function() {
        scope.bulb = controller.getState();
      });
    }
  };
});


  - 변경내역 : toggle off일 경우

  <div class="btn btn-success ng-binding disabled" power-switch="">
     
      SWITCHED OFF
     
    <div class="bulb off" ng-class="bulb" lightbulb=""></div></div>


  - 결과 화면 : uppercase 필터 사용



5-11. Scope

  - scope가 hierarchy하게 생성/유지되면 element와 부모 element사이의 scope를 설정한다.

  - 그러나 자신은 부모 Scope하고만 바인드되어 data에 접근 할 수 있다. 최상위 scope는 $rootScope 객체이다

  - scope: false

    + 새로운 scope 객체를 만들지 않고 부모가 가진 같은 scope 객체를 공유한다

  - scope: true

    + 새로운 scope 객체를 만들고 부모 scope 객체를 상속받는다 


  - index.html 내역

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive : parent -> child depth  -->
    <div class='well'>
      Bound to $rootScope: <input type="text" ng-model="parent">
      <div child></div>   
    </div>
 
    <div class='form well' ng-controller="OneCtrl">
      ng-controller="OneCtrl"<br/>
     
      <input type="text" ng-model="children"><br/>
      I am {{children}} and my grandfather is {{parent}}
     
      <div child></div>
    </div>
  </body>
 
</html>


  - script.js 내역 : child 디렉티브의 link에서 conole.log(scope)를 찍어본다

var App = angular.module('App', []);

App.run(function($rootScope) {
    $rootScope.parent = 'ROOT';
});

App.directive('child', function() {
    return {
        restrict: 'A',
        // scope: false,
        scope: true,
        template: 'I am a directive and my father is {{parent}} as well as {{children || "NIL"}}',
        link: function(scope, element, attrs) {
            console.log(scope);
        }
    };
});

App.controller('OneCtrl', function($scope) {
    $scope.children = 'The One';
});


  - 결과화면 : child의 scope: true, false로 변경해 가면서 console.log의 내역을 비교해 본다

 

  - scope: true

// 첫번째 child의 $parent객체를 보면 ROOT이다


// 두번째 child의 $parent 객체를 보면 controller의 scope.children='The One' 값이 보임. 즉, controller scope가 부모이다


// Chrom에서 보면 scope 구조도가 보인다



  - scope: false

// 첫번째 child의 $parent객체를 보면 ROOT이다


// 두번째 child의 $parent 객체를 보면 ROOT 이다


// 002 는 ROOT scope 이고 그 밑으로 controller scope만 존재하고 child는 이것을 공유한다




  - scope: 'isolate'

    + 부모 scope를 상속받지 않는다. 그러나 scope.$parent로 부모 scope를 억세스 할 수 있다 

    + iscope.$parent을 사용하지 않고 isolated scope와 부모 scope간의 데이터 공유방법은 어떻게 하는가?

       isolated scope는 당신이 부모 scope로 부터 properties를 끌어내어 local scope와 바인드하는 object/hash를 갖는다  

       1) @ : 부모 scope property local scope 값을 바인딩한다. 원하는 값 전달시 {{}} 를 사용한다

       2) = : 부모 scope (전달전 측정되어질) property 를 직접 바인딩 한다  

       3) & : 속해있는 scope context안에서 수행될 expression 또는 method 바인딩 한다 

 

  - prefix parent property @, children property =, shout() method & 를 준 예제

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>

  </head>

  <body>
    <h1>Hello Angular</h1>
    <!-- 3) add angular directive : parent -> child depth  -->
    <div class='well'>
      Bound to $rootScope: <input type="text" ng-model="parent">
      <div child parent='{{parent}}' shout="shout()"></div>   
    </div>
 
    <div class='form well' ng-controller="OneCtrl">
      ng-controller="OneCtrl"<br/>
      <input type="text" ng-model="children"><br/>
      I am {{children}} and my grandfather is {{parent}}
      <div child parent="{{parent}}" children="children" shout="shout()"></div>   
    </div>

  </body>
 
</html>


  - script.js 내역

r App = angular.module('App', []);

App.run(function($rootScope) {
    $rootScope.parent = 'ROOT';
   
    $rootScope.shout = function() {
        alert("I am bound to $rootScope");
    };
});

App.directive('child', function() {
    return {
        restrict: 'A',
        scope: {
            parent: '@',
            children: '=',
            shout: '&'
        },
        template: '<div class="btn btn-link" ng-click="shout()">I am a directive and my father is {{parent || "NIL"}} as well as {{children || "NIL"}}</div>'
    };
});

App.controller('OneCtrl', function($scope) {
    $scope.children = 'The One';
   
    $scope.shout = function() {
        alert('I am inside ng-controller');
    };
});


  - 결과화면

 

  * scope: isolate 에 대한 이해는 egghead.io 사이트를 참조한다



5-12. Transcude

  - ngTransclude를 통하여 DOM에 transcluded DOM을 insert 할 수 있다

  - transclude: true
    transcluded DOM을 template에서 ngTransclude directive에 삽입한다

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">

  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
    <!-- 3) template -->
    <script type='text/ng-template' id='whoiam.html'>
      <div class="thumbnail" style="width: 260px;">
        <div><img ng-src="{{data.owner.avatar_url}}" style="width:100%;"/></div>
        <div class="caption">
          <p><b>Name: </b>{{data.name}}</p>
          <p><b>Homepage: </b>{{data.homepage}}</p>
          <p><b>Watchers: </b>{{data.watchers}}</p>
          <p><b>Forks: </b>{{data.network_count}}</p>
          <marquee ng-transclude></marquee>
        </div>
      </div>
    </script>
</head>

<body style='padding:30px;'>
  <div whoiam>I got transcluded</div>
</body>
</html>



// script.js

var App = angular.module('App', []);

App.directive('whoiam', function($http) {
   return {
     restrict: 'A',
     transclude: true,
     templateUrl: 'whoiam.html',
     link: function(scope, element, attrs) {
       $http.get('https://api.github.com/repos/angular/angular.js').success(function(data) {
         scope.data = data;
       });
     }
   };
 });



// DOM 내역

<div whoiam="">

  <div class="thumbnail" style="width: 260px;"><div>

   <img style="width:100%;" ng-src="https://secure.gravatar.com/avatar/f0d91e5cf8ad1ce7972cc486baa20c42?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-org-420.png" src="https://secure.gravatar.com/avatar/f0d91e5cf8ad1ce7972cc486baa20c42?d=https://a248.e.akamai.net/assets.github.com%2Fimages%2Fgravatars%2Fgravatar-org-420.png"></img>

</div>


<div class="caption">

  <p class="ng-binding"> … </p>

  <p class="ng-binding"> … </p>

  <p class="ng-binding"> … </p>

  <p class="ng-binding"> … </p>

  <marquee ng-transclude="">

    <span class="ng-scope">
      I got transcluded
    </span>

  </marquee>

 </div>


// 결과 화면 : I got transcluded 메세지가 오른쪽에서 왼쪽으로 움직인다


  - transclude: 'element'

    + transclude link function을 compile function안에 정의한다

// index.html

<!DOCTYPE html>
<!-- 1) add the ng-app attribute -->
<html ng-app="App">
  <head>
    <!-- 2) add the angular library -->
    <script data-require="angular.js@1.1.5"
      data-semver="1.1.5"
      src="http://code.angularjs.org/1.1.5/angular.min.js"></script>
    <link rel="stylesheet" type="text/css" href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css">
    <link href="style.css" rel="stylesheet" />
    <script src="script.js"></script>
</head>

<body style='padding:30px;'>
  <div transclude-element>I got transcluded <child></child></div>
</body>
</html>


// script.js

var App = angular.module('App', []);
App.directive('transcludeElement', function() {
    return {
        restrict: 'A',
        transclude: 'element',
        compile: function(tElement, tAttrs, transcludeFn) {

           // return 펑션이 link 펑션이 된다. 해당 펑션안에서 scope 객체 데이터 바인딩을 제어한다
            return function (scope, el, tAttrs) {
                transcludeFn(scope, function cloneConnectFn(cElement) {
                    tElement.after('<h2>I was added during compilation </h2>').after(cElement);
                });
            };
        }
    };
});

App.directive('child', function(){
    return {
        restrict: 'E',
        link: function($scope, element, attrs) {
            element.html(' with my child');
        }
    };
});


// DOM 내역

<body style="padding:30px;">
      <!-- transcludeElement:  -->
    <div class="ng-scope" transclude-element="">
      I got transcluded
      <child>
         with my child
      </child>

    </div>

    <h2>
      I was added during compilation
    </h2>

</body>


// 결과 화면



<참조>

  - 원문 : The Hitchhiker’s Guide to the Directive

  - Scoep Isolate 참조 : egghead.io 사이트

  - Yeoman 사용하기

posted by 윤영식
2014. 8. 3. 23:26 AngularJS/Concept

AngularJS를 배우기 위해 좌충우돌 하며 읽고, 보고, 듣고, 코딩해본 코스를 나름 정리해 보았다. 




1. 개념잡기

  - Angular's father인 미스코님의 AngularJS 소개 동영상을 본다 : 단계별로 jQuery와 잘 비교하고 있다

    

  - Art of AngularJS를 보고서 이제 배워야할 필요성을 느껴보세요. 이제 시작하세요. 

    


  - AngularJS의 중요 요소와 기본기를 다져보자 (60분 동강)

    

     + AngularJS 전체 구성 요소 : 각각에 대해 간단히 알아보자

   

      + AngularJS 흐름

   


  - 개발자 가이드에서 Bootstrap, HTML Compiler, Conceptual Overview, Directives 를 꼭 읽는다 (내 포스팅에도 정리했다)

  - AngularJS 홈페이지에서 제공하는 튜토리얼 보기

  - 요약 정리 내역을 다시 보자




2. 프로토타입핑 해보기

  - 전체 flow를 간단히 코딩해 보자

  - egghead.io 에서 모든 동강을 따라해 본다 : 100개 넘는 강좌가 있고 짧은 대신 꼭 코딩해본다 

    

  - AngularJS 팀의 Meetup 동영상들 보기 : Angular 기능별 설명을 해준다 (이건 개당 1시간씩 넘어서 틈틈히 보자)

    + Best Practices :  미스코님이 직접 설명한다.

    

  - AngularJS에서의 Deferred and Promise에 대한 이해

    

  - http://www.yearofmoo.com/ 의 AngularJS 강좌들 코딩

    + Use AngularJS to Power

    + More AngularJS Magic

  - AngularJS Design Patterns 

  - MEAN Stack 사용 예제 : MEAN is MongoDB + Express + AngluarJS + Node.js




3. Angular 생태계

  - Angular-UI : Twitter Bootstrap, Grid 등 지속적으로 AngularJS Directives 를 만들어 내고 있다 

  - angular modules는 http://ngmodules.org/ 먼저 찾아보자

    

  - angular-strap : http://mgcrea.github.io/angular-strap/

  - Learn AngluarJS : Thinkster.io

  - AngularJS-Tips




4. 데이터 연동

  - AngularJS에서 제공하는 $resource를 사용하여 RESTful 하게 개발한다

    + 동영상에서 $resource를 어떻게 사용하는지 익히자 (GitHub Demo 소스)

    

  - RestangularJS를 이용한  RESTful 서버 연동

  - Real-time을 위한 AngularJS와 Socket.io 연동하기 seed 구성




5. 개발환경 구축하기 

  - 개발 소스 코드 저장소는 DVCS인 Git + GitHub 을 사용한다 : Git 을 통하여 성공적인 브랜칭 전략을 세우자

  - Yeoman을 통하여 AngularJS의 스케폴딩 소스를 만들어 개발한다 : AngularJS 개발환경 구성하기

  - Yeoman generator Angular 와 Express.js 연동하기




6. 참여와 공유

  - AngularJS 구글 그룹스 참여

  - 공개 그룹 활동하기

    + Facebook AgularJS 오픈 그룹 

    + Google+ AngularJS 오픈 그룹 

  - JSFiddle을 통하여 예제파일 공유하기

  - StackOverflow 통하여 Q&A 하기

  - AngularJS 트위터 팔로잉

최근 -213.10.11- 으로 AngularJS에 대한 관심이 높아지고 있고, 다양한 블로그와 관련 글이 많이 올라오고 있다. 이중 AngularJS 배우기의 종결자 블로깅을 들어가서 배워보자 



7. AngularJS v1.* 에서 v2.* 으로  
  - AngularJS는 올해 v2.* 버전이 나올 예정이고 큰 변화를 예고 하고 있다. 하지만 이것은 피할 수 없는 대세로 보여진다. 이유는 간단하다. 좀 더 단순하고 좀 더 성능이 뛰어나며 인지 가능한 단순 문법으로 하는 길로 가고 있다. 
  - v1.* 에서 v2.* 로 바뀌니 어쪄냐고 호들갑 떨지 말자. v1.*도 쓰지 않으면서 v2.* 의 변화를 논하지도 말자. 지금 당장 v1.*를 써보고 좀 더 쉽게 웹 애플리케이션을 개발해 보는 경험이 중요하다. v2.*가 성숙할 때 쯤이면 우리는 더 많은 변화 앞에 놓여 있을 것이다. 
  - v2.* 간결함과 Web Components, ECMAScript 6 로의 방향의 핵심은 Componen를 사용한 Composition 패턴의 애플리케이션이라 보며 새롭지도 않으며 어렵지도 않은 방향으로 대중적으로 사용할 수 있게 만들어 가는 능력에 찬사를 보낸다. 땡큐 AngularTeam!!!
  
  



8. Directives $compile 서비스에 대한 이해 

2015 ng vegas에서 발표한 $compile에 대한 구현과정을 상세히 설명하고 있다. 예로 대시보드 빌더를 개발한다고 했을 때 대시보드 화면에 차트를 가져다 놓을 때 차트에 대한 디렉티브가 있다고 하면 동적으로 디렉티브를 컴파일하고 $scope와 링크를 맺우어주어야 한다. 이런 일련의 과정이 어떻제 진행되는지 알 수 있다. 또한 디렉티브에 대한 상호 관계로 상속(Inheritance)와 격리(Isolate)부분도 설명한다.  

- 발표 동영상 

  
  
  발표중에 나온 장표 

  




<참조>

  - 배우는 과정을 잘 요약한 블로깅 : http://blog.whydoifollow.com (강추)

  - AngularJS 내용 요약 (필독)

  - Angular v1.3 변경 사항들

  - 몇가지 참조할 만한 사이트 

    + AngularJS 포스팅 in codingsmackdown.tv

       tiny -> medium -> large project 확장하는 방법 (소스)

    + 페이지 플래그먼트의 라우팅 : http://onehungrymind.com/building-a-website-with-angularjs-routes-and-partials/

    + $apply 사용 이유http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

    + $provide 사용 : http://slides.wesalvaro.com/20121113/#/

    + AngularJS에서 Dependency Injection에 대한 이해

    + 요분 유명하다 와인샐러 샘플 : http://coenraets.org/blog/2012/02/sample-application-with-angular-js

    + 전체 구성요소 설명

    + Directive 통하여 재사용가능 컴포넌트 만들기

    + Lazing Loading in AngularJS

    + Animation in AngularJS

    + AngularJS CheetSheet

  - 처음 개발할 때 8가지 유용한 개발 접근법 ($rootScope, $locationProvider 사용예)



posted by 윤영식
2014. 6. 28. 19:07 Big Data/ElasticSearch

ElasticSearch(이하 ES) 엔진에 수집된 데이터에 대하여 Kibana 도움 없이 직접 Data Visualization 하는 기술 스택을 알아보고, 실데이터를 통한 화면 1본을 만들어 본다. 




ES 시각화를 위한 다양한 방식의 시도들


사전조사-1) 직접 클라이언트 모듈 제작하여 Data Visualization 수행 

  - elasticsearch.js 또는 elatic.js 사용하지 않고 REST 호출 통해 데이터 시각화 수행 

    (Protovis 는 D3.js 기반 Chart를 사용함)

  - FullScale.co에서는 dangle 이라는 시각화 차트를 소개

    (D3.js 기반의 AngularJS Directives 차트)

  - D3.js 기반의 전문적인 차트를 사용하는 방법을 익힐 수 있다. 하지만 제대로 갖춰진 ES 클라이언트 모듈의 필요성 대두


사전조사-2) elasticsearch.js 사용하여 Data Visualization 수행

  - elasticsearch.js와 D3.js, jquery, require.js를 통해서 샘플 데이터를 시각화 수행

    (AngularJS는 사용하지 않고, 전문적인 차트 모듈사용하지 않음)

  - AngularJS 기반으로 Protovis 또는 Dangle 차트를 사용하여 표현해 본다.


사전조사-3) elastic.js 사용하여 Data Visualization 수행

  - elastic.js 홈페이지에서 API를 숙지한다.

  - DSL API를 살펴보자. DSL을 이해하기 위해서는 ES의 Search API에 대한 이해가 필요하다.

  - Query를 작성하고 Filtering 하면 group by having과 유사한 facets (지금은 aggregation 을 사용)하여 검색을 한다.

    Query -> Filter -> Aggregation에 대해 알면 DSL구성을 이해할 수 있다.

  - 자신의 Twitter 데이터를 가지고 elastic.js와 angular.js를 사용하여 트윗 내용을 표현하는 방법 (GitHub 소스)




ES Data Visualization을 위한 나만의 Tech Stack 만들기 


  - ES 클라이언트 모듈 : elastic.js 의 DSL(Domain Specific Language)를 숙지한다. 

    elastic.js는 ElasticSearch의 공식 클라이언트 모듈인 elasticsearch.js 의 DSL 화 모듈로 namespace는 ejs 이다.  

  - 시각화를 위한 D3.js 의 개념 이해 (D3.js 배우기)

  - Kibana에서 사용하고 있는 Frontend MV* Framework인 AngularJS (AngularJS 배우기)

  - AngularJS 생태계 도구인 yeoman 을 통해 개발 시작하기 (generator-fullstack,  Yeoman 사용방법)

  - 물론 Node.js는 기본이다. 


그래서 다음과 같이 정리해 본다. 


  - AngularJS 기반 Frontend 개발

    1) Node.js 기초

    2) Yeoman + generator-angular 기반 

  - D3.js 기반의 Chart 이며 AngularJS 바로 적용가능토록 Directives 화 되어 있는 차트 중 선택사용

    1) Protovis

    2) Dangle

    3) Angular nvd3 charts (추천)

    4) Angular-Charts

    5) Angular Google Charts 

  - elasticsearch.js를 DSL로 만든 elastic.js 사용


그래서 다시 그림으로 정리해본 기술 스택



ES Data Visualization 개발을 위한 구성 stack 그림






== 이제 만들어 봅시다!!! ==


 

환경설정

  - node.js 및 yeoman 설치 : npm install -g generator-angular-fullstack 설치 (generator-angular는 오류발생)

  - twitter bootstrap RWD 메뉴화면 구성 (기본 화면 구성)

  - angular-ui의 angular-bootstrap 설치 :  bower install angular-bootstrap --save

  - elasticsearch.js 설치 : bower install elasticsearch --save

  - elastic.js 설치 : bower install elastic.js --save

  - angular-nvd3-directives chart 설치 : bower install angularjs-nvd3-directives --save



angular layout 구성 

  - 애플리케이션 생성 : GitHub Repository를 만들어서 clone 한 디렉토리에서 수행하였다

$ git clone https://github.com/elasticsearch-kr/es-data-visualization-hackerton 

$ cd es-data-visualization-hackerton 

$ yo angular-fullstack esvisualization

  - main.html 과 scripts/controllers/main.js 를 주로 수정함 

// main.html 안에 angular-nvd3.directives html 태그 및 속성 설정 

    <div class="row">

      <div class="col-xs-12 col-md-12">

        <div class="panel panel-default">

          <div class="panel-heading">

            <button type="button" ng-click="getImpression()" class="btn btn-default">Impression Histogram</button>

          </div>


          <div class="panel-body">


            <!-- angular-nvd3-directives : multi-bar chart -->

            <div class="col-xs-12 col-md-12">

              <nvd3-multi-bar-chart

                  data="impressionData"

                  id="dataId"

                  xAxisTickFormat="xAxisTickFormatFunction()"

                  width="550"

                  height="350"

                  showXAxis="true"

                  showYAxis="true">

                    <svg></svg>

              </nvd3-multi-bar-chart>

            </div>


          </div>

        </div>

      </div>

    </div>



// main.js 안에서 elasticsearch.js를 직접 호출하여 사용함 

angular.module('esvisualizationApp')

  .controller('MainCtrl', function ($scope, $http) {


    // x축의 값을 date으로 변환하여 찍어준다 

    $scope.xAxisTickFormatFunction = function(){

      return function(d){

        return d3.time.format('%x')(new Date(d));

      }

    }


    // 화면에서 클릭을 하면 impression index 값을 ES에서 호출하여 

    // ES aggregation json 결과값을 파싱하여 차트 데이터에 맵핑한다

    $scope.getImpression = function() {


      // ES 접속을 위한 클라이언트를 생성한다 

      var client = new elasticsearch.Client({

                                              host: '54.178.125.74:9200',

                                              sniffOnStart: true,

                                              sniffInterval: 60000,

                                            });


// search 조회를 수행한다. POST 방식으로 body에 실 search query를 넣어준다 

      client.search({

          index: 'impression',

          size: 5,

          body: {

            "filter": {

                "and": [

                    {

                      "range": {

                        "time": {

                            "from": "2013-7-1", 

                            "to": "2014-6-30"

                        }

                      }

                    }

                ]

            },

            "aggs": {

              "events": {

                "terms": {

                  "field": "event"   

                },

                "aggs" : {   

                  "time_histogram" : {

                      "date_histogram" : {

                          "field" : "time",

                          "interval" : "1d",   

                          "format" : "yyyy-MM-dd" 

                      }

                  }

                }

              }

            }


            // End query.

          }

      }).then(function (resp) {

         var impressions = resp.aggregations.events.buckets[0].time_histogram.buckets;

         console.log(impressions);


         var fixData = [];

         angular.forEach(impressions, function(impression, idx) {

          fixData[idx] = [impression.key, impression.doc_count];

         });

   

   // 결과에 대해서 promise 패턴으로 받아서 angular-nvd3-directives의 데이터 구조를 만들어 준다

   // {key, values}가 하나의 series가 되고 배열을 가지면 다중 series가 된다. 

         $scope.impressionData = [

            {

              "key": "Series 1",

              "values": fixData

            }

          ];


  // apply 적용을 해주어야 차트에 데이터가 바로 반영된다.

        $scope.$apply();

      });

    }


  });




결과 화면 및 해커톤 소감

  - "Impression Histogram" 버튼을 클릭하면 차트에 표현을 한다.

  - elastic.js의 DSL을 이용하면 다양한 파라미터에 대한 핸들링을 쉽게 할 수 있을 것같다. 

  - AngularJS 생태계와 elasticsearch.js(elastic.js)를 이용하면 Kibana의 도움 없이 자신이 원하는 화면을 쉽게 만들 수 있다. 

  - 관건은 역시 ES에 어떤 데이터를 어떤 형태로 넣느냐가 가장 먼저 고민을 해야하고, 이후 분석 query를 어떻게 짤 것인가 고민이 필요!



* 헤커톤 소스 위치 : https://github.com/elasticsearch-kr/es-data-visualization-hackerton



<참조> 

  - elasticsearch.js 공식 클라이언트 모듈을 DSL로 만든 elastic.js 

  - elastic.js를 사용한 ES Data Visualization을 AngularJS기반으로 개발

  - Protovis 차트를 이용한 facet 데이터 표현

  - ElasticSearch Data Visualization 방법

  - D3.js 와 Angular.js 기반으로 Data Visualization

  - ElasticSearch의 FacetAggregation 수행 : 향후 Facet은 없어지고 Aggregation으로 대체될 것이다.

  - AngularJS Directives Chart 비교

posted by 윤영식
2014. 6. 17. 14:33 AngularJS/Concept

이제 모든 서비스는 모바일 먼저 기획을 하고 웹 서비스로 넘어가야 한다고 생각한다. 즉, Contents -> UX -> Design -> Develop -> Launch로 넘어가면서 그 기본은 모바일이 먼저이다. 기존에 Bootstrap을 사용했을 경우 RWD (Response Web Design)이 적용되어 해상도에 따른 사용자 경험을 데스크탑과 모바일에 준하게 줄 수 있었지만 네이티브 앱과 유사한 UX 경험을 제공하기에는 부족하다. HTML5 기반으로 개발을 한다면 RWD 외에 Mobile First 전략을 가지고 있는 하이브리드 웹앱 Framework을 살펴 볼 필요가 있다. 살펴볼 두가지의-ionic, onsenui - 하이브리드 앱(모바일 웹앱) 프레임워크는 PhoneGap + Angular.js 와 결합되는 형태를 취하고 있다. mobile angular ui는 PhoneGap과 연결시키는 별도의 작업을 수반한다. 




                       




Ionic 하이브리드 웹앱 프레임워크

  - Ionic 홈페이지

  - PhoneGap에 최적화 되어 프로젝트를 생성해 준다.

  - https://github.com/driftyco/ionic-starter-sidemenu 처럼 ionic-starter-xx의 sidemenu, tabs, blank 3가지 타입을 제고하고 있다

// 설치 

$ sudo npm install -g cordova 

/usr/local/bin/cordova -> /usr/local/lib/node_modules/cordova/bin/cordova

cordova@3.5.0-0.2.4 /usr/local/lib/node_modules/cordova


$ sudo npm install -g ionic

/usr/local/bin/ionic -> /usr/local/lib/node_modules/ionic/bin/ionic

ionic@1.0.14 /usr/local/lib/node_modules/ionic


// 프로젝트 생성

$ ionic start myAppSideMenu sidemenu

Running start task...

Creating Ionic app in folder /Users/prototyping/myAppSideMenu based on sidemenu project

DOWNLOADING: https://github.com/driftyco/ionic-app-base/archive/master.zip

DOWNLOADING: https://github.com/driftyco/ionic-starter-sidemenu/archive/master.zip

Initializing cordova project.

Fetching plugin "org.apache.cordova.device" via plugin registry

Fetching plugin "org.apache.cordova.console" via plugin registry

Fetching plugin "https://github.com/driftyco/ionic-plugins-keyboard" via git clone


$ cd myAppSlideMenu


  - ionic 수행

$ ionic platform add android

Running platform task...

Adding platform android

.. 생략 ..

Project successfully created.

Installing "com.ionic.keyboard" for android

Installing "org.apache.cordova.console" for android

Installing "org.apache.cordova.device" for android


$ ionic build android

Running build task...

Building platform android

Running command: /Users/prototyping/myAppSideMenu/platforms/android/cordova/build

Buildfile: /Users/prototyping/myAppSideMenu/platforms/android/build.xml

... 중략 ...

-post-build:

     [move] Moving 1 file to /Usersprototyping/myAppSideMenu/platforms/android/ant-build

     [move] Moving 1 file to /Users/prototyping/myAppSideMenu/platforms/android/CordovaLib/ant-build

debug:

BUILD SUCCESSFUL

Total time: 48 seconds


// Android의 AVD를 먼저 실행해야 한다 

$ ionic emulate android

Running emulate task...

Emulating app on platform android

Running command: /Users/nulpulum/development/studygps_company/prototyping/myAppSideMenu/platforms/android/cordova/run --emulator

... 중략 ...

BUILD SUCCESSFUL

Total time: 9 seconds

Installing app on emulator...

Using apk: /Users/prototyping/myAppSideMenu/platforms/android/ant-build/HelloCordova-debug-unaligned.apk

Launching application...

LAUNCH SUCCESS


-- AVD 통해 본 모습

  

* 안드로이드 AVD 관리하기 (참조)


 - ionic 분석

 - ionic 명령을 통하여 ionic 프레임워크와의 통합 빌드작업을 자동 수행해 준다

// 완벽하게 angular.js 기반으로 운영된다 (angular.js v1.2.12 버전 번들링)

// www/lib/ionic/js/ionic.bundle.js 


// index.html 

<!DOCTYPE html>

<html>

  <head>

    <meta charset="utf-8">

    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

    <title></title>


    <link href="lib/ionic/css/ionic.css" rel="stylesheet">

    <link href="css/style.css" rel="stylesheet">


    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above

    <link href="css/ionic.app.css" rel="stylesheet">

    -->


    <!-- ionic/angularjs js -->

    <script src="lib/ionic/js/ionic.bundle.js"></script>


    <!-- cordova script (this will be a 404 during development) -->

    <script src="cordova.js"></script>


    <!-- your app's js -->

    <script src="js/app.js"></script>

    <script src="js/controllers.js"></script>

  </head>


  <body ng-app="starter">

    <ion-nav-view></ion-nav-view>

  </body>

</html>

  - ionic components



Onsen UI 프레임워크 

  - PhoneGap을 설치와 Onsen ui 설치는 별개로 진행된다. 따라서 ionic과 같이 PhoneGap에 대한 기본 지식이 필요하다  

  - Onsen ui는 angular.js directive를 제공하는데 주력한다

  - PhoneGap 환경 설정 

// PhoneGap

$ npm install -g cordova

$ cordova create MyAppOnsenui && cd MyAppOnsenui

Creating a new cordova project with name "HelloCordova" and id "io.cordova.hellocordova" at location "/Users/prototyping/MyAppOnsenui"

Downloading cordova library for www...

Download complete


$ cordova platform add android

Creating android project...

Creating Cordova project for the Android platform:

Path: platforms/android

Package: io.cordova.hellocordova

Name: HelloCordova

Android target: android-19

Copying template files...

Running: android update project --subprojects --path "platforms/android" --target android-19 --library "CordovaLib"

Resolved location of library project to: /Users/prototyping/MyAppOnsenui/platforms/android/CordovaLib

Updated and renamed default.properties to project.properties

..중략..

Project successfully created.


-- build와 emulate 전에 하기의 Onsen ui 설치와 설정을 먼저 한 후에 수행한다 


$ cordova build android

.. 중략 ..

BUILD SUCCESSFUL

Total time: 32 seconds


-- android의 AVD를 먼저 실행해야 한다 

$ cordova emulate android


  - Onsenui components : 가장 기본적인 것들을 제공함 

  - Phonegap과 Angular.js 의 결합을 개발자가 직접해야함 

  - 활발한 Community feedback이 없는 상태이다 (참조)

  - Onsenui설치

// Onsen ui

$ cd MyAppOnsenui


$ bower init  명령으로 bower.json 파일을 만들거나 기존의 generator-angular-fullstack의 것을 사용한다

bower install onsenui --save

{

  "name": "mobiconsoft-mobile-app",

  "version": "0.1.0",

  "dependencies": {

    "angular": ">=1.2.*",

    "json3": "~3.3.1",

    "es5-shim": "~3.2.0",

    "angular-resource": ">=1.2.*",

    "angular-cookies": ">=1.2.*",

    "angular-sanitize": ">=1.2.*",

    "angular-ui-router": "~0.2.10",

    "restangular": "~1.4.0",

    "jquery": "1.11.1",

    "modernizr": "~2.8.1",

    "console-shim": "*",

    "jStorage": "~0.4.8",

    "angular-gettext": "~0.2.9",

    "ladda-studygps": "~0.9.4",

    "angular-ladda-studygps": "~0.1.7",

    "onsenui": "~1.0.4"

  },

  "devDependencies": {

    "angular-mocks": ">=1.2.*",

    "angular-scenario": ">=1.2.*"

  },

  "testPath": "test/client/spec"

}


-- http://onsenui.io/OnsenUI/project_templates/sliding_menu_navigator.zip 에서 샘플 파일을 다운로드 받아서 app 폴더에 있는 것을 www 폴더로 복사한다. 그리고 index.html안에 cordova.js를 넣는다. (개발시에는 404 NOT Found 발생함)


cordova build android

cordova emulate android

-- AVD로 띄워본 결과

 


  - Sliding Menu에 있어서는 Ionic 보다는 Onsenui가 좀 더 세련되어 보임 



Mobile Angular UI

  - Slide Menu 와 기본적인 모바일 화면 구성 컴포넌트를 angular.js 기반으로 Directive화 해놓았다. 

  - 친숙한 Bootstrap 기반의 UI를 제공한다. 그러나 Twitter bootstrap의 RWD기반은 아니다



ngCordova

    

  - cordova에서 제공하는 API를 angular 에서 사용할 수 있도록 Angular Service로 만들어 놓았음



좀 더 잘 정비된 것을 쓰고 싶다면 Ionic을 기초 기술부터 체크하면 갈 것이라면 Onsenui를 추천한다. 또한 좀 더 세련되 UI는 Onsenui에 점 수를 더 주고 싶다. 그리고 서로의 아키텍쳐에 대한 부분과 커스터마이징 여부는 좀 더 들여다 보아야 할 것으로 보인다. 각각의 상황과 특성에 따라 선택하여 사용하면 될 것으로 보인다. 



<참조>

  - Ionic 시작하기 

  - onsenui 시작하기

  - onsenui sliding menu zip 

sliding_menu_navigator.zip


  - mobile angular ui

  - iSO 8 UI Framework 7

  - ngCordova

  - 용어 정의 

    

posted by 윤영식