AWS Summit 2017. IoT와 AI.


AWS에서 많은 서비스를 제공하고 있지만, 지금 사용하는 서비스는 몇 가지 되지 않는다.
아마존 웹 서비스를 쓰면서 서비스 운영에 대한 부담이 많이 줄었으니 또 좋은 서비스가 눈에 띄면 써보고 싶은데,
문서 찾기가 영 까다롭다.
그래서 가끔은 이런 행사에 가서 정보를 얻는다.
이틀 동안 진행하는 행사였는데, 목요일 하루 오후에만 잠깐 다녀온 게 좀 아쉽지만,
제일 관심 있던 IOT와 AI 세션을 들었으니 만족한다.
이번 행사에서 가장 흥미로웠던 건 오프라인 환경에서 IOT 기기의 소통을 돕는 AWS greengrass였다.
이를 통해 정보기술 서비스를 적용하기 어려웠던 분야에 혁신이 이루어지길 기대해본다.

AWS Summit 2017 서울, 메모

AWS 기반 고급 하이브리드 IT 디자인

Direct connect (https://aws.amazon.com/ko/directconnect/)

비용

Port 사용비용/시간 + 데이터 전송료
데이터 IN $0, 데이터 아웃 - 리전별 상이
회선(전용선/MPLS) 비용
로케이션 상면 임대비용(필요시)
트래픽이 많으면 전용선을 쓰는게 오히려 비용 절감이 된다.

성능

1 Gbps 10Gbps
DX파트너를 통해 100, 200, 300, 400, 500 Mbps 까지 가능
VPC 까지 통신할 때는 VPC peering을 사용한다. (dev, test, production VPC)
원하는 수준의 네트워크 가용성을 가질 수 있다.

Amazon SNS로 지속적 관리가 가능한 대용량 푸쉬 시스템 구축 여정

레거시

GCM, APNS 이용해서 1000건씩 끊어 보냈음.
시간 오래걸리고 상태와 모니터링 어려움

SNS (https://aws.amazon.com/ko/sns/)

Topics : 어플리케이션 엔드포인트들이 구독 단위로 그루핑 되어있음
Application : 플랫폼 별 토큰
Subscriptions : 어플리케이션이 토큰을 구독하는 정보

aws 콘솔에서 csv토큰 등록할 때 오류발생 : cli나 api를 이용하자.
이벤트가 발생할 때마다 SQS에 넣고 람다로 파싱해서 로그를 관리 (예 : 발송 이벤트가 발생하면 해당 토큰이 발송 완료되었다는 것을 표시해두고 중복 전송을 막는다.)
병렬처리할 때 동일 데이터를 끌고가면 중복 푸쉬가 발생하는걸 염두에 두자.
APNS 어플리케이션 인증은 1년마다 만료되므로 미리미리 갱신해두자.
SNS - CloudWatchLogs 기록 IAM 설정해두자.

그룹 전송

조건에 일치하는 사용자 목록을 뽑아서 큐에 넣고 람다를 통해 SNS로 발송
회원 가입할 때 토픽을 정의해둔다.

AWS와 Docker Swarm을 이용한 쉽고 빠른 콘테이너 오케스트레이션

Docker swarm (https://docs.docker.com/engine/swarm/)

클러스터 구성 / ECS보가 몇가지 나은 기능도 있다.
멀티메니저 노드 지원
다양한 서비스를 연결해 사용해야 할 때 고려해볼 만 하겠다.
Docker for AWS (Cloud formation)
오토스케일링 설정 가능
클라우드와치 지원

docker network

동일 네트워크에 컨테이너를 등록
Ingress Network : 모든 노드에 포트를 오픈한다.
visualizer service로 각 노드의 상태를 알 수 있다.

AWS IoT 기반 사물 인터넷 아키텍쳐 구현하기

https://aws.amazon.com/ko/iot/

기능

Device gateway : MQTT와 HTTP(1.1)를 이용한 Thing과의 커뮤니케이션
Device sdk : 연결, 인증, 메시지교환
Rules Engine : 규칙 기반으로 메시지 변환 및 AWS 서비스로 전달 (sql로 토픽 필터 정의)
Rule Engine Action :
하나의 토픽에 여러 룰을 적용해서 연동
Shadow : 기기가 오프라인일 때 마지막 상태를 알아내거나 다음 동작을 저장해둠. (일종의 캐쉬로 보면 되겠다. 파이어베이스db처럼)

구성 축

Thing : Sense, act
Cloud : storage, computing
Intelligence : analysis

AWS Greengrass(https://aws.amazon.com/ko/greengrass/)

로컬 이벤트에 신속히 반응할 수 있음
오프라인 운영가능
디바이스에서 데이터 처리 가능
클라우드 비용 절감

AWS Greengrass 구성

  • 로컬 브로커
  • 로컬 람다
  • 로컬 디바이스 쉐도우
데이터 온도에 따라 다른 접근이 필요하다.
Hot - Kinesis, Warm - Lambda , Cool, Cold

Amazon AI 서비스를 통한 스마트 애플리케이션 개발

https://aws.amazon.com/amazon-ai/

Polly

텍스트를 음성으로 변환
SSML 지원 : 음선 합성을 위한 W3C레서 정한 XML 기반 언어 규약
Lexicons : 개발자가 단어의 실제 발음을 정의
텍스트 - 어떻게 읽을지 텍스트 문장 - 발음으로 변환 - 높낮이 규정 - 음성 스트리밍으로 변환
MP3로 다운받아 재사용 가능
cli, sdk로 사용 가능
aws polly
백만문자당 $4

Amazon Recognition API

이미지에서 객체 및 장면을 탐지해서 json으로 반환
안면인식, 비교
민감한 정보를 포힘하고 있는지 알려줌

Amazon Lex

쉬운 쳇봇 구현
콘솔에서 정의해서 바로 런칭 가능
versioning, alias 제공



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

파이어베이스 커스텀 토큰을 이용한 데이터베이스 접근권한 설정하기


파이어베이스 데이터베이스에 조건에 따라 접근권한을 다르게 하려고 커스텀 토큰을 이용하게 되었다.
커스텀 토큰을 만들고 파이어베이스에 규칙을 적용한 다음 테스트를 해보려고 했는데 REST API에 JWT토큰을 아무리 넣어봐도 작동하지 않았다.

?auth=CUSTOM-TOKEN 파라미터로도 넣어 보았고,
Authorization: bearer CUSTOM-TOKEN 헤더로도 넣어 보았지만

"error" : "Permission denied"
"error" : "Expected an ID token, but was given a custom token." 같은 오류만 보여줄 뿐이었다.

REST에서 커스텀 토큰을 사용할 방법을 한참 찾다가 FireBase Rest with auth query param not working(http://stackoverflow.com/questions/39117237/firebase-rest-with-auth-query-param-not-working)이라는 글에서 답을 찾았다.

REST API 에서는 커스텀 토큰을 사용할 수 없다.

REST에서 커스텀 클레임을 사용하기 위해서는, auth_variable_override 파라미터를 사용해야 한다.
{"uid":"6LiF16Dm0hNB9XO61UR1KM5Jeun2"}
위의 uid를 사용한다면 아래처럼 요청해야 한다.
$ curl "https://dbname.firebaseio.com/test.json?access_token=&auth_variable_override=%7B%22uid%22%3A%226LiF16Dm0hNB9XO61UR1KM5Jeun2%22%7D" {" 1213314":{"alanisawesome":"Alan Turing"}}


결국 파이어베이스의 커스텀 토큰을 테스트하려면 파이어베이스 라이브러리를 사용해야 한다.
그래서 파이어베이스 커스텀 토큰 테스트를 위한 예제 프로젝트를 node.js로 간단히 만들었다.
아래 예제를 따라 하면 파이어베이스의 커스텀 토큰으로 데이터 베이스 접근 권한을 제어하는 흐름을 볼 수 있다.

커스텀 토큰으로 데이터 베이스 접근 권한 설정하기(https://github.com/dorajistyle/firebase-custom-token-sample/blob/master/readme-ko.md)


참고

https://firebase.google.com/docs/admin/setup
https://firebase.google.com/docs/auth/cpp/custom-auth
https://firebase.google.com/docs/auth/admin/create-custom-tokens
https://firebase.google.com/docs/reference/security/database
http://stackoverflow.com/questions/37426093/using-custom-tokens-to-make-rest-requests-to-fb-db-as-an-admin
http://stackoverflow.com/questions/39117237/firebase-rest-with-auth-query-param-not-working
https://jwt.io/



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

젠킨스 CI에서 레일즈+Postgres 테스트하기


젠킨스는 오픈소스 지속적 통합관리(Continuous Integration) 도구로 자바기반이다.

소스를 git이나 svn 같은 형상관리(CM : configuration management) 서버에 올리면, 그때마다 자동으로 테스트도 하고, 빌드도하고, 작업이 잘 끝났다고 알림도 주는 도구다.

자바기반이기 때문에 다른 언어로 개발된 애플리케이션을 젠킨스에서 테스트 하려면 따로 환경 설정이 필요하다. 이번엔 루비 온 레일즈로 만들어진 애플리케이션 테스트를위해 환경을 설정해 보았다.

레일즈 테스트용 젠킨스 도커 설정은 https://github.com/dorajistyle/jenkins-rails-postgres-docker 에서 볼 수 있다.

우선 아래 명령어로 소스를 다운 받는다.

git clone https://github.com/dorajistyle/jenkins-rails-postgres-docker.git


그리고 아래 명렁어로 도커 컨테이너를 빌드하면 젠킨스가 실행된다. docker-compose.yml에 나와있듯이 docker compose를 이용해서 postgres와 redis를 jenkins와 함께 실행하도록 하였다.

docker-compose up


젠킨스에서 레일즈를 테스트하기 위한 순서는 다음과 같다.

  1. 터미널에서 admin암호를 복사해서 젠킨스에 붙여 넣는다.
  2. 유저 정보를 입력해서 젠킨스를 시작한다.
  3. Multi-configuration 프로젝트를 만든다.
  4. Source Code Management 에서 git를 선택한다.
  5. 아래 url을 Repository URL 필드에 붙여넣는다.
    https://github.com/dorajistyle/rails-postgres-sample-for-jenkins

    만약 오픈소스가 아닌 프로젝트를 테스트 하려면, Credential을 추가해 줘야 한다.
    Add를 눌러 Username and password방식을 선택하고, username에는 github ID를 넣고 password에는 https://github.com/settings/tokens에서 생성한 토큰을 넣으면 된다.
  6. Build Environment에서 rbenv build wrapper체크박스를 선택한다.
    The Ruby version에는 2.3.1을 넣고,
    Preinstall gem list에는 bundler,rake,execjs를 넣는다.
  7. Add build step 샐랙트박스에서 Execute shell를 선택한다.
    Command필드에 아래 명령어를 붙여 넣는다.
    bash jenkins-test.sh
  8. 만약 빌드가 될 때 마다 슬랙으로 알림을 주고 싶다면, 플러그인을 설정해줘야 한다.
    우선 github 프로젝트의 설정에 젠킨스 플러그인을 추가해준다.
    Settings--> Webhooks&Services-->Service--> Add Services--> Choose "Jenkins (GitHub plugin)"
    에서 추가하고 아래 주소를 넣어준다.
    http:///github-webhook/
    https://.slack.com/apps/A0F7VRFKN-jenkins-ci 에서 Jenkins CI 앱 설정을 해준다.
    Post-build Actions의 Add post-build action 선택상자에서 Slack Notifications를 선택하고 환경 정보를 넣어준다.
    토큰은 슬랙 앱 설정에 나온 토큰을 넣어주면 된다.
  9. 설정을 저장하고 프로젝트의 사이드메뉴에서 Build Now를 클릭하여 테스트한다.

Docker compose로 띄운 
젠킨스에서 레일즈 테스트가 잘 돈다.

* rails 설정의 database.yml에는 docker-compose로 설정한 컨테이너 이름(예제 : dorajistyle-postgres)을 쓰고,
config.yml의 redis설정에도 마찬가지로 컨테이너 이름(예제 : dorajistyle-redis)를 써야 한다.


* git fetch 타임아웃 발생시 해결
Source Code Management > Git > Additional Behaviors > Advanced checkout behaviors / Advanced clone behaviors > Timeout (in minutes)



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

Multi-container 도커 애플리케이션 쉽게 쓰기. Docker Compose


Docker는 참으로 편리한 도구다. Dockerfile만 한번 잘 작성해 두면, 두고두고 잘 쓸 수 있다. 그러나 한 가지 아쉬운 점이 있다면, 복잡한 서비스는 Dockerfile이 지나치게 길어진다는 것이다. 데이터베이스와 캐시, 애플리케이션 설정을 한데 모아두면 오류가 났을 때 무엇이 문제인지 찾기도 어렵다.
그래서 각각의 설정을 따로 만들어서 실행 시에 --link 옵션으로 연결하기도 하지만, 귀찮은 일이다.
Docker compose는 그런 귀찮음을 줄여준다. 아래 docker compose 설정 파일을 보자.


docker-compose.yml
version: '2'
services:
postgres:
container_name: mypostgres
image: postgres
ports:
- "5432:5432"
redis:
container_name: myredis
image: redis
ports:
- "6379:6379"
webapp:
build: .
container_name: myapp
restart: always
ports:
- "80:8080"
depends_on:
- postgres
- redis


이렇게 설정 파일을 만들고,
docker-compose up
명령어만 실행하면 애플리케이션을 실행하기 전에 postgres와 redis를 띄우고 나서, webapp 컨테이너를 띄워준다.
webapp에서 해당 컨테이너에 접속하려면 host에 container_name을 넣어주면 된다.
예를 들어 postgres에 접속하려면 host에 mypostgres를 넣어주면 된다.
docker compose 덕분에 도커 컨테이너 관리의 신세계가 열렸다.

아마존 AWS의 EC2 Container service 에서도 docker compose 파일을 지원하기 때문에, 쉽게 배포할 수 있다.
다만 로컬 이미지를 지원하지 않으므로 Amazon EC2 Container Registry(ECR)에 이미지를 올려 사용해야 한다.
만약 배포해야하는 multi-container docker가 많다면 ECS를 고려해볼 만 하다.
하지만 ECS task를 실행하기 위해서는 인스턴스를 하나 올려야 하므로, 올려야 할 서비스가 많지 않다면 그냥 EC2 인스턴스 하나에서 docker-compose up 명령어를 사용해 띄우는 것이 경제적이다.
꼭 ECS를 사용하지 않더라도 오픈소스가 아닌 이미지 저장용으로 ECR은 쓸만하다.
따로 Docker registry를 위한 인스턴스를 띄우지 않아도 되고, 스토리지 요금과 데이터 전송 요금만 사용한 만큼 내면 되기 때문에 간편하다.


참고자료

https://docs.docker.com/compose/rails/
https://docs.docker.com/compose/compose-file/
https://docs.docker.com/compose/startup-order/

AWS ECS 관련

http://docs.aws.amazon.com/AmazonECS/latest/developerguide/launch_container_instance.html
https://aws.amazon.com/ko/ecr/
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_installation.html
http://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_Configuration.html
https://github.com/aws/amazon-ecs-cli
https://aws.amazon.com/ko/ecr/pricing/?nc1=h_ls



by


Tags : , , , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

인터넷 익스플로러 9 이하에서 CORS(Cross-origin resource sharing) 설정.

정적인(static) 파일은 보통 CDN(Contents Delivery Network)과 연결하여 사용자에게 빠르게 전달한다.
사용자 입장에선 빠르게 콘텐츠를 받아볼 수 있어 좋고,
관리자 입장에선 서버에 부담을 줄여줘서 좋다.
그러나 외부 CDN을 이용할 땐 주의해야 한다.
인터넷 익스플로러 대마왕이 CDN을 편히 쓰도록 가만히 놔두질 않기 때문이다.
만약 스타일 시트를 CDN에 올려놨다면, 인터넷 익스플로러에서 처참하게 망가진 화면을 만나게 될 것이고,
Ajax로 CDN 서버에 요청을 한다면 404 오류코드(파일은 내가 처리했다. 다음은 너 차레야라는 뜻.)를 만나게 된다.
이것은 재앙이며, 개발자에겐 악몽을 선사한다.

우리나라는 1999년 전자서명법을 시행하면서 액티브X를 중심으로 하는 공인인증제가 도입됐다.
이것이 인터넷 익스플로러 대마왕의 힘을 키워준 것이 되었고,
웹 개발자(특히 한국 개발자)는 새천년 밀레니엄의 시작과 함께 인터넷 익스플로러 대마왕과 힘겨운 싸움을 이어와야 했다.
최근에는 인터넷 익스플로러에서 보안 결함이 발견되어 영국과 미국 정부에서 인터넷 익스플로러를 쓰지 말라는 권고를 내리기도 했었다.
(http://www.telegraph.co.uk/technology/microsoft/10793272/Dont-use-Internet-Explorer-warns-US-government.html)
물론 이 문제가 패치 되긴 했지만(http://techcrunch.com/2014/05/01/microsoft-patches-latest-internet-explorer-security-flaw-even-for-xp-users),
인터넷 익스플로러는 여전히 골칫거리여서,
'인터넷 익스플로러 쓰지 마세요.'(http://donotuseie.com)라는 사이트가 있을 정도다.

마음 같아서는 인터넷 익스플로러를 무시하고 개발하고 싶다.
그러나, 한국에선 인터넷 익스플로러가 갑이다.
인터넷 익스플로러에서만 돌아가는 웹사이트가 수두룩하기 때문이다.
'한국 사람들은 인터넷 익스플로러를 써요. 법이거든요.'(http://www.zdnet.com/south-koreans-use-internet-explorer-its-the-law-7000022827)라는 기사에서도 볼 수 있듯,
우리나라는 인터넷 익스플로러 사용자 인구가 많다.
게다가 10부터는 그나마 좀 나은데, 우리나라는 8을 제일 많이 쓴다.
statcounter 작년 5월부터 올해 5월까지 통계를 뽑아보니 한숨이 나온다.

브라우저 이용 현황, 한국-'인터넷 익스플로러(IE) 9이하에서  CORS 설정'

그럼 전 세계적으로는 어떤 브라우저를 많이 쓸까?

브라우저 이용 현황, 전세계-'인터넷 익스플로러(IE) 9이하에서  CORS 설정'

크롬이 압도적이고, 다음은 파이어폭스다.
하지만 한국의 개발자가 웹 어플리케이션을 만들려면, IE8 이상은 지원해야 된다.
대한민국은 인터넷 익스플로러 강국이니까.

인터넷 익스플로러(IE) 9이하에서 CORS 설정.

CDN서버에 CORS 설정을 해 두고, 아래 코드를 적용하면 된다.

우선 CSS를 제대로 보여주기 위한 Respond.js 설정이다.

마크업

여기에서 static_path는 CDN서버의 주소이다.
<!DOCTYPE html>
...
<html><head>
<!--[if lt IE 9]><>
<script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
<link href="#{static_path}/js/vendor/respond-proxy.html" id="respond-proxy", rel="respond-proxy">
<link href="/ie/respond/respond.proxy.gif" id="respond-redirect", rel="respond-redirect">
<script src="/ie/respond/respond.proxy.js"></script>
<![endif]--></head>...</html>


서버단 flask

/ie로 요청이 들어오면, 어플리케이션의 루트안에 ie폴더에서 파일을 찾아 응답한다.
@app.route('/ie/')
def base_static(filename):
print('app root path '+str(app.root_path))
print('app filename '+str(filename))
return send_from_directory(app.root_path + '/ie/', filename)

그리고 jQuery ajaxTransport XDomainRequest(https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest)를 다운받아 jquery 다음에 불러 놓으면,
인터넷 익스플로러에서 자동으로 CORS처리를 해준다. 내겐 이게 제일 간편하고 좋았다.

인터넷 익스플로러의 횡포가 계속된다면 '한국에서 인터넷 익스플로러를 무찌를 레이드 파티 구합니다.'라는 공고가 올라올지도...?

참조



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

크롬 개발자들이 들려주는 개발 노하우. Chrome developer day.

오랜만에 오프라인 강연을 들었습니다.
Chrome developer day.
평소 사용하는 Devtool 활용법과 PageSpeed 세션을 들으려고 갔어요.
PageSpeed는 뭔가 새로운 팁을 듣고 싶었는데 일반적인 이야기뿐이라 좀 아쉬웠습니다.
그래도 원래 들으려던 강연 말고도 전체적으로 만족스러웠어요.
특히 렌더링 관련 강연이 좋았습니다.
또 이런 좋은 행사가 열리면 찾아들어야겠어요.:D


신기술

flex-direction과 Position: sticky등 CSS와
Geolocation, Orientation등 자바스크립트 기능을 소개했다.
가장 눈에 띄었던 건 Offline events인데 네트워크에 연결되지 않은 상태라면 웹사이트에서 이를 인식한다. 이걸 이용하면 오프라인시에 웹에서 안내를 제공하면 되겠다.
localSotrage, Websql, indexdb 세 종류의 storage API도 소개했다.
semantic input types는 사용성 향상에 도움을 준다.
성능 측정이 필요하면 navigation timing API나 Resource timing API를 쓰면 된다.
그 밖에도 Camera, Web audio, getuserMedia, Web rtc(real time communication), webGL, android intend (QR) 등도 간략히 소개했다.


Polymer 라이브러리.

Web components.
DOM 엘리멘트로 되어있어 친숙하다.
그러나 템플릿 코드와 혼재하여 사용하면 코드가 지저분해지겠다.


DevTools

workspace를 이용하면 페이지 새로 고침을 하지 않고 실시간으로 확인할 수 있다.
workspace를 사용하려면 resource에서 원하는 파일을 add to workspace로 추가 해 주어야 한다.
sass와 less도 지원한다.

모바일 웹 환경에서 리모트 디버깅(https://developers.google.com/chrome-developer-tools/docs/remote-debugging)을 사용하면 편리하다.

타임라인(https://developers.google.com/chrome-developer-tools/docs/timeline)

  • 파랑은 로딩(Loading)
  • 노랑은 스크립팅(Scripting)
  • 보라색은 렌더링(Rendering - Recalculate Style)
  • 녹색은 그리기(Paint)

적절한 타임라인 순서 예시

  • Function Call
  • Recalculate Style
  • Layout
  • Paint Setup
  • Paint
  • Composite Layers

DevTools 페이지에 들어갔다가 테마를 입맛에 맞게 바꾸는 법을 발견해서 취향대로 바꿨다.
zerodarkmatrix(https://github.com/mauricecruz/chrome-devtools-zerodarkmatrix-theme)테마 참 잘 만들었다. 테마는 아래 폴더에 넣으면 된다.
Chromium: ~/.config/chromium/Default/User\ StyleSheets/

Html5 Games

Canvas, WebGL(OpenGL ES 2.0)(2007년에 나왔는데 IE11에서 이를 지원한다.), WebAudio, Fullscreen API, Pointer lock API, Web Workers, PNaCl(Portable Native Client) 등의 라이브러리를 이용하여 게임을 개발하면 된다.


Chrome Apps

  • 오프라인에서 동작(Offline by default)
  • 클라우드 친화적(Cloud ready)
  • OS에 자연스럽게 통합(Natively Integrated)
  • 다양한 장치 지원(Multi device support)

하드웨어를 제어할 수 있다.
Phonegap(http://phonegap.com/)을 이용하면 크롬 앱을 안드로이드나 iso 플랫폼 앱으로 변환할 수 있다.


성능

  • Element를 모두 렌더링 하는 것은 아니고 보이는 것만 렌더링 한다.
  • 모바일에서 touch시에 클릭 이벤트는 300ms를 기다려야 하니 touch 이벤트 리스너를 사용하여 지연을 줄여준다. (Canjs에선 touchstart 이벤트를 사용하면 되겠다.)
  • 1초에 60프레임 보여주려면 최대 지연율이 16.67ms 이하여야 한다.
  • 에니메이션 함수에 setTimeout(function, 16.67)을 이용한다.(http://stackoverflow.com/questions/729921/settimeout-or-setinterval)
  • redirect 쓰지 말자. 외부 api를 쓸때 dns lookup이 여러번 일어나는데 dns prefetch를 이용하면 성능이 향상된다.
  • CSS animation에

    {
    -webkit-transform: translateZ(0);
    -moz-transform: translateZ(0);
    -ms-transform: translateZ(0);
    -o-transform: translateZ(0);
    transform: translateZ(0);
    }

    를 이용해 GPU 가속을 활성화한다. (이건 핵이다.)
  • 웹 페이지 성능을 알아보려면 Pagespeed extension을 이용한다.
  • ATF(http://whatis.techtarget.com/definition/above-the-fold) 컨텐츠가 처음 15kb안에 배달되야 한다.(https://developers.google.com/speed/docs/insights/PrioritizeVisibleContent)

배치를 바꿀 때 transform을 이용하는 게 좋다고 하나, 문서(http://blog.tumult.com/2013/02/28/transform-translate-vs-top-left/)를 찾아보니 transition을 사용하지 않는다면 top/left로 위치를 잡는 것이 더 빠르단다. 심지어 불투명한 요소만 포함하고 있다면 GPU 가속 핵을 사용하지 않는 것이 더 빠르다. 배터리 소모도 고려해야 하므로 핵을 쓸 땐 잘 생각해서 쓴다.


Dartlang(https://www.dartlang.org)

구조화된 웹 앱을 개발을 돕는 새로운 개발 언어.
이미지 처리에 강점을 보인다니, 혹 게임을 만들 일이 생기면 한번 써봐야겠다.



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

파이썬 Flask에서 RequireJS Optimizer를 이용한 static폴더 최적화.

자바스크립트MVC를 이용할 경우 자바스크립트와 뷰 템플릿때문에 static폴더가 무겁습니다.
파일의 공백을 모두 제거하여 용량을 줄이면 좀 가벼워 지지요.
허나 파일 공백을 없애면 가독성이 떨어집니다.
난감한 상황이 발생해요.
길이 1m짜리 한줄코드를 고치고 기능 추가하는건 어렵잖아요?
변경이 빈번하게 일어나는 static 폴더.
개발 편의와 성능 두마리 토끼를 잡을 좋은 수가 없을까요?
RequireJS를 이용해 자바스크립트를 관리하신다면 방법이 있습니다!

우선 노드JS(http://nodejs.org)를 설치합니다.

RequireJS Optimizer를 설치합니다.

npm install -g requirejs

3. r.js를 다운로드 받습니다.(http://requirejs.org/docs/release/2.1.8/r.js)

4. 예제에서 사용할 어플리케이션 디렉토리 구조는 다음과 같습니다.

/build
  - r.js
  - build.js
/application
  __init__.py
  /static
    /views
      template.ejs
    /js
      app.js
      /vendor
        jquery-1.10.1.min.js
        bootstrap.min

application/init.py

from flask import Flask
app = Flask(__name__)
# static 폴더 경로를 지정해 줍니다. debug일땐 ‘static’폴더로 경로를 설정하고 나머지는 ‘static-build’를 경로로 잡습니다.
app.static_folder = 'static-build'
if app.debug:
        app.static_folder = 'static'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

application/static/js/app.js

자바스크립트 어플리케이션 파일입니다.
requirejs의 기본 설정을 담고 있습니다.

require.config({
    "baseUrl": "/static/js",
    "paths": {
        "jquery": [
            "//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min",
            "vendor/jquery-1.10.1.min"
        ],
        "jquery.bootstrap": [
            "//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/js/bootstrap.min",
            "vendor/bootstrap.min"
        ],
    },
    shim: {
        "jquery.bootstrap": {
            deps: ["jquery"],
            exports: '$.fn.bootstrap'
        },
        enforceDefine: true
    }
});

requirejs(['jquery','jquery.bootstrap'],
    function ($) {
    // 어플리케이션 코드 
    }
);

/build/build.js

RequireJS용 build파일입니다.

{
    appDir: '../application/static',
    baseUrl: 'js/vendor',
    mainConfigFile: '../application/static/js/app.js',
    paths: {
        "jquery": "jquery-1.10.1.min",
        "jquery.bootstrap": "bootstrap.min",
    },
    dir: '../application/static-build',
    optimize: "uglify2",
    optimizeCss: "standard.keepLines",
    removeCombined: true, // combine된 파일은 남겨두지 않습니다.
    preserveLicenseComments: false,
    modules: [
        {
            name: '../app'
        }
    ]
}

프로젝트 루트 페이지에서 다음을 실행합니다.

JS/CSS파일을 최적화 하여 application/static-build 폴더에 저장합니다.
node ./build/r.js -o ./build/build.js

단 이는 js와 css만 최적화를 해 주기 때문에 Ejs 템플릿도 용량을 줄이려면 아래 커맨드를 이용하면 됩니다.
find ./application/static-build/views -name '*.ejs' -exec sed -i '/^\s∗\/\//d' {} \;
find ./application/static-build/views -name '*.ejs' -exec sed -i 's/^[ \t]*//g; s/[ \t]*$//g;' {} \;
find ./application/static-build/views -name '*.ejs' -exec sed -i ':a;N;$!ba;s/\n/ /g' {} \;

쉘 스크립트를 작성해 한번에 실행하면 간편합니다.

optimizer.sh

#!/bin/sh
cd './build'
node ./r.js -o build.js
cd '../application/static-build/views'
find . -name '*.ejs' -exec sed -i '/^\s∗\/\//d' {} \;
find . -name '*.ejs' -exec sed -i 's/^[ \t]*//g; s/[ \t]*$//g;' {} \;
find . -name '*.ejs' -exec sed -i ':a;N;$!ba;s/\n/ /g' {} \;

참고 자료



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

파이썬 flask 개발 문서 만드는데 5분. Sphinx.

문서 작성도 개발의 일환입니다.
개발자는 깔끔한 문서를 만들고 싶지만,
문서 작성에 많은 시간을 들이고 싶지는 않지요.
Sphinx가 바로 그 딜레마를 해결해 주는 도구입니다.


Sphinx로 파이썬 Flask 개발 문서 만들기 순서

  1. Sphinx와 sphinxcontrib-httpdomain를 설치합니다.
    $ pip install sphinx
    $ pip sphinxcontrib-httpdomainproject 폴더에 doc 폴더 생성합니다.
  2. doc 폴더로 갑니다.
  3. sphinx-quickstart를 실행하여 기본 설정을 잡습니다.
    $ sphinx-quickstart
  4. conf.py에 다음을 추가합니다.
    sys.path.append(os.path.abspath('..'))
    # 확장
    extensions = ['sphinx.ext.autodoc',
    'sphinx.ext.intersphinx',
    'sphinxcontrib.autohttp.flask']
    # 테마 (default|basic|sphinxdoc|scrolls|agogo|traditional|nature|haiku|pyramid)
    html_theme = "nature"

    기본으로 제공하는 테마 외에도 내려받거나 직접 만든 테마도 사용 가능합니다.
  5. rst파일을 생성합니다.
    API 예시
    Users
    --------------------------
    .. autoflask:: application.api:create_app()
    :undoc-static:
    # api에 포함시키고 싶지 않은 blueprints.
    :undoc-blueprints:
  6. 문서를 생성합니다.
    $ make html

참고 자료

http://sphinx-doc.org/tutorial.html
http://sphinx-doc.org/theming.html
http://pythonhosted.org/sphinxcontrib-httpdomain/



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

개발이 끝났다면? NGINX서버와 supervisor를 써서 배포해 봅시다.

NGINX

/etc/nginx/nginx.conf
http {
keepalive_timeout 65;
gzip on;
add_header Cache-Control private;
gzip_static on;
gzip_http_version 1.1;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
gzip_types application/x-javascript text/css *;

map $http_x_requested_with $nocache {
default 0;
XMLHttpRequest 1;
}

include /etc/nginx/sites-enabled/*;
}

/etc/nginx/sites-available/myapp.conf

server {
listen 80;
server_name _;

root /path/myapp;

access_log /path/myapp/logs/access.log;
error_log /path/myapp/logs/error.log;

proxy_cache_bypass $nocache;
proxy_no_cache $nocache;

location /static {
expires modified +24h;
alias /path/myapp/application/frontend/static-build;
}

location /api/_uploads {
expires modified +24h;
alias /path/myapp/images;
}

location / {
proxy_pass http://127.0.0.1:8000;
proxy_redirect off;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_read_timeout 30;
}
}

* static 폴더를 설정할 때 주의 점
root를 사용할 땐 static 폴더의 상위 폴더를 지정하고,
alias를 사용할 땐 static폴더를 지정한다.

Upload file size setting
client_max_body_size

권한이 필요합니다. 오류 해결.
error log.
2013/07/10 18:31:54 [crit] 23626#0: *127 stat() "PATH" failed (13: Permission denied) request: "GET PATH HTTP/1.1", host: "localhost", referrer: "http://localhost/"
chmod 751 PATH
all path in PATH should have access permission.
PATH에 모든 경로에 접근 권한이 필요하다.
예) /home/example/applications/myapp 경로에 접근해야 할 땐.
/ , /home, /home/example, /home/example/application, /home/example/applications/myapp 에 접근 권한이 필요하다.

location 설정
인덱스 파일이 없을때 오류 처리와 디렉토리 목록을 보여준다.
autoindex on;

설정 파일 심볼릭 링크 걸기
ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/

Arch Linux 기준 nginx 서버 실행과 정지.
sudo systemctl start nginx
sudo systemctl stop nginx


supervisor

/etc/supervisor.d/myapp.ini
[program:myapp]
command = gunicorn --debug --log-level debug -w 4 -b 127.0.0.1:8000 wsgi:application
; command = twistd web --port 5000 --wsgi wsgi.application
directory = /path/myapp
user = root
autostart=true
autorestart=true
; stdout_logfile=NONE
; stderr_logfile=NONE
; Handy for debugging:
stdout_logfile=/var/log/supervisor/webapp.stdout
stderr_logfile=/var/log/supervisor/webapp.stderr

supervisor 실행법
데몬 실행(테스트를 위해 프론트에서 실행함)
sudo supervisord -n
변경사항을 다시 읽고 업데이트 함.
sudo supervisorctl reread
sudo supervisorctl update
supervisor 실행
sudo supervisorctl start myapp
supervisor 재실행
supervisorctl restart webapp


※ 만약 고정 아이피에서 서비스를 한다면 gunicorn을 실행할 때 localhost가 아닌 고정 아이피 주소(예: gunicorn -b 123.456.789.000:8000)로 실행해야 외부에서 접근이 가능하다.
물론 nginx설정도 그에 맞게 변경해야 한다.

참고 자료



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

데이터베이스 마이그레이션 관리를 간편하게! alembic.

alembic은 파이썬 SQLAlchemy DB Toolkit과 연동하여 마이그레이션 관리를 돕는 편리한 도구입니다.

프로젝트 폴더로 가서 alembic을 초기화 한다.
alembic init alembic

alembic.ini파일에서 데이터 베이스를 설정해 준다.
sqlalchemy.url = mysql://scott:tiger@localhost/test

마이그레이션을 자동으로 생성하기 위해 다음을 alembic/env.py에 추가한다.
import os, sys
sys.path.append(os.getcwd())
from application import db
target_metadata = db.Model.metadata

* 자동 생성에서는 테이블명이나 컬럼명을 변경한 것은 감지하지 못한다.

다음 커멘드를 이용해 자동으로 마이그레이션을 생성한다.
alembic revision --autogenerate -m "Added account table"

DB를 새 마이그레이션으로 업그레이드 하려면?
alembic upgrade head

원하는 마이그레이션으로 업그레이드 하거나 다운그레이드 하려면?
$ alembic upgrade +2
$ alembic downgrade -1

alembic 튜토리얼



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

Canjs와 Flask를 이용한 웹개발 예제

클라이언트 사이드 자바스크립트 프레임워크인 Canjs와
파이썬 마이크로 프레임워크인 Flask를 이용한 웹 어플리케이션 예제입니다.
이 Canjs + Flask 예제가 프레임워크 이해에 도움이 되길 바랍니다.


Canjs + Flask 예제 소스


예제에 사용된 라이브러리

  • Canjs, 클라이언트 사이드 자바스크립트 프레임워크.
  • RequireJS, 자바스크립트 파일•모듈 로더.
  • Initializr, HTML5 템플릿.
  • Bootstrap, 프론트엔드 프레임워크.
  • JSDoc, 자바스크립트 문서화 도구.
  • BusterJS, 자바스크립트 테스팅 도구.
  • mustache, 템플릿 엔진.
  • i18next, 자바스크립트 다국어 도구.
  • Flask, 가벼운 파이썬 프레임워크.
  • Flask-SQLAlchemy, SQLAlchemy의 플라스크 플러그인.
  • Jade(pyjade), 파이썬용 Jade 템플릿 엔진 플러그인.
  • Flask-Babel, 플라스크용 다국어 플러그인.

예제의 이해를 돕는 글



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

잘 짜여진 자바스크립트 MVC 프레임워크. Canjs

Backbone, AngularJS, Spine….
그동안 나왔던 자바스크립트 프레임워크를 조금씩 건드려는 보았지만,
항상 아쉬움이 남았습니다.
이번에 Canjs를 써보니, 정말 잘 만들어진 프레임워크라는 생각이 들어요.
자바스크립트MVC 프레임워크를 써 볼까 생각 중이시라면, Canjs 한번 고려해 보세요.

can.Control

컨트롤러에서 이벤트 처리

"li .destroy {Event.destroy}": function( el, event) {
var todo = el.closet('li').data('todo);
todo.destroy();
event.stopPropagation();}
});
Events = {destroy : "click"};

css Selector, html.getElementBy, $(selector)가 Control의 셀렉터로 사용된다.

When the element your Control is bound to is removed from the DOM,
the Control destroys itself, cleaning up any bound event handlers.

can.Control 이 아는 이벤트.
* change
* click
* contextmenu
* dblclick
* focusin
* focusout
* keydown
* keyup
* keypress
* mousedown
* mouseenter
* mouseleave
* mousemove
* mouseout
* mouseover
* mouseup
* reset
* resize
* scroll
* select
* submit

링크 처리 방법(How can I make a link in Canjs?)

레이어(layer)
<a id="id" href="javascript://">href</a>

페이지(page)
<a id="id" href="#!id">href</a>

무스타치에서 콜백 받기(Mustache Element Callback)

{{data 'model'}}

경로 설정(RequireJS Paths)

requireJS can require is /can
requireJS에서 canJS를 쓸 땐 can.js를 패스로 잡고 사용해야 한다.
registerHelper이용을 위해서는 can/view/mustache가 필요하다.

404루트 잡기(How to define a catch all route to handle 404 in can js?)

http://stackoverflow.com/questions/13824665/how-to-define-a-catch-all-route-to-handle-404-in-can-js

can.route.bind('change', function(ev, newVal) {
if (newVal === 'route') {
var valid = false;
$.each(can.route.routes, function(k,v) {
if (new RegExp(v.test).test(window.location.hash)){
valid = true;
return; //exit loop
}
})
if (!valid) {
//handle the false route here
}
}
});

다국어 지원(Localization)

Localization is a good example of a custom helper you might implement in your application. The below example takes a given key and returns the localized value using jQuery Globalize.

1. Mustache.registerHelper('l10n', function(str, options){
2. return Globalize != undefined
3. ? Globalize.localize(str)
4. : str;
5. });

can.route에서 i18next 데이터를 받아오지 못할 때

can.when을 이용하여 초기화가 된 후 can라우팅 처리를 해 준다.


var lang =utils.getParam('lang');
var i18noption = {debug: true};
lang != undefined
? i18n
option.lng = lang
: i18n_option.lng = "en";
can.when(i18n.init(i18n_option)).then(function (){});

모델 관계(model associations)

https://forum.javascriptmvc.com/topic/questions-about-model-associations

<div class="header">
<h1>Association</h1>
</div>
<!-- YOUR CODE HERE -->
<div id="contacts"></div>

can.fixture("/contacts.json", function(){
return [{
'id': 1,
'name' : 'Justin Meyer',
'birthday': '1982-10-20',
tasks : [{
id: 1,
title: "write up model layer",
due: "2010-10-5"
}]},{
'id': 2,
'name' : 'Brian Moschel',
'birthday': '1983-11-10',
tasks : [{
id: 2,
title: "write up funcunit",
due: "2009-5-1"
},{
id: 3,
title: "test funcunit",
due: "2010-3-15"}]
},{
'id': 3,
'name' : 'Bobby Joe',
'birthday': '1980-2-10'
}];
})

can.Model.convert.date = function(raw){
if(typeof raw == 'string'){
var matches = raw.match(/(\d+)-(\d+)-(\d+)/);
return new Date( +matches[1],
(+matches[2])-1,
+matches[3] );
}else if(raw instanceof Date){
return raw;
}
};

// A task model that has a date
can.Model("Task",{
attributes : {
due : 'date',
}
},{
weeksPastDue : function(){
return Math.round( (new Date() - this.due) /
(1000*60*60*24*7 ) );
}
});

// A contact model that has many tasks
can.Model("Contact",{
attributes : {
birthday : 'date',
tasks: "Task.models"
},
findAll : "/contacts.json"
},{
ageThisYear : function(){
return new Date().getFullYear() -
this.birthday.getFullYear()
},
getBirthday : function(){
return ""+this.birthday.getFullYear()+
"-"+(this.birthday.getMonth()+1)+
"-"+this.birthday.getDate();
}
});

// Get all contacts and put them on the page
Contact.findAll({},function(contacts){
var contactsEl = can.$('#contacts');

can.each(contacts, function(contact){
var li = can.$('<li>')
.html(contact.name + " "+ contact.ageThisYear())
.appendTo(contactsEl);

var ul = can.$("<ul>");
var tasks = contact.attr('tasks')

if(tasks){
tasks.each(function(){
this.attr('contact', contact);
ul.append('<li>'+this.title+" "
+this.weeksPastDue()+' contact: '+ this.attr('contact.name') +'</li>')
});
}

ul.appendTo(li)
});
});

 

Canjs 웹사이트



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

Javascript 모듈 관리엔 RequireJS

자바스크립트 모듈이 많아 관리가 어렵다면, RequireJS를 사용 해 보세요.

설정(Configuration)


require.config({
"baseUrl": "/static/js/vendor",
"paths": {
"app": "../app",
"bootstrap": [
'//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min',
"bootstrap"
],
"jquery": [
"//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min",
"jquery-1.9.1.min"
],
"can": "can",
shim: {
"bootstrap": {
deps: ["jquery"],
exports: "$.fn.popover"
},
enforceDefine: true
}
}
});

모듈 정의(define function)


define(["jquery"],function($){
return {
getParam: function(paramname){
var value = new RegExp('[\?&]' + param
name + '=([^&#]*)').exec(window.location.href);
return value[1];
},
test: function(text){
console.log("test : "+text);
}
};
});

두 모듈을 한 파일에 넣는 방법(requirejs, two classes in one file)

http://stackoverflow.com/questions/9806940/requirejs-two-classes-in-one-file

define('test', ['jquery'], function() {
var exports = {};
exports.test1 = {
method1 : function () {
console.log("test1 - method 1");
},
method2 : function () {
console.log("test1 - method 2");
}
};
exports.test2 = {
method1 : function () {
console.log("test2 - method 1");
},
method2 : function () {
console.log("test2 - method 2");
}
};

return exports;
});

그리고 아래처럼 사용하면 된다.
require(['test'], function (test) {
var test1 = test.test1;
});

두 모듈을 한 파일에 넣는 다른 방법
http://blog.credera.com/topic/technology-solutions/java/modular-javascript-with-requirejs


define(['json!data/customers'], function(customers){
var getRow = function(id) {
return customers[id];
};

var getAll = function() {
return customers;
};

var update = function(data) {
// do something cool with the data
};
return {
get: getRow,
list: getAll,
update: update
};
});


오류 해결

  • Jquery CDN경로가 올바르지 못할 경우 Bootstrap로딩에 오류가 난다.
  • 같은 모듈(예: bootstrap)이 중복 로드될 경우 충돌이 일어난다.

RequireJS 홈페이지



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

자바스크립트용 개발 문서 작성기. JSDOC

주석 달기


/** define namespace
* @namespace category
*/

/** use namespace with hash
* @name category#name
* @constructor
*/

/** use member of for constructor
*@memberof category#name
*/


설정(configuration)

remove all comments.
// You must remove the comments before adding these options to your .json file

{
"tags":{
"allowUnknownTags":true
},
"source":{
"include":[],
"exclude":[],
"includePattern":".+\.js(doc)?$",
"excludePattern":"(^|\/|\\)_"
},
"plugins":[],
"templates":{
"cleverLinks":false,
"monospaceLinks":false
},
"opts":{
"template":"default", // same as -t default
"encoding":"utf8", // same as -e utf8
"destination":"./out/", // same as -d ./out/
"recurse":true, // same as -r
"tutorials":"path/to/tutorials",// same as -u path/to/tutorials, default "" (no tutorials)
"query":"value", // same as -q value, default "" (no query)
"private":true, // same as -p
"lenient":true, // same as -l
// these can also be included, though you probably wouldn't bother
// putting these in conf.json rather than the command line as they cause
// JSDoc not to produce documentation.
"version":true, // same as --version or -v
"explain":true, // same as -X
"test":true, // same as -T
"help":true, // same as --help or -h
"verbose":true, // same as --verbose, only relevant to tests.
"match":"value", // same as --match value, only relevant to tests.
"nocolor":true // same as --nocolor, only relevant to tests
}
}


실행
jsdoc -c conf.json

JSDOC github



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

파이썬 Flask 플러그인 안내와 팁.

데이터베이스
Flask-SQLAlchemy : OR매핑을 지원하는 플라스크용 파이썬 SQL toolkit
SQLAlchemy에서 상속(Inheritance) : http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html

SQLAlchemy 컬럼에 데이터가 생성될때나 업데이트 될때 현재 시각을 자동으로 넣는 방법.
updated_at = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())

로그인·보안
Flask-Social : 소셜 네트워크와의 연결을 간편하게 해 줌.
Flask Security(Auth) : 로그인과 권한관리.

관리자 페이지
Flask-Admin : 관리자 페이지를 손쉽게 만들도록 도와줌.

다국어 지원
Flask-Babel : 파이썬용 다국어 지원 Babel의 Flask 플러그인

캐쉬
flask-cache : 캐쉬 설정을 도와줌.

에셋 관리
flask-assets : 각종 static 에셋 관리를 편하게 도와줌.
사용하고자 하는 기능에 따라 추가 모듈이 필요하다. (css 압축, scss사용)
pip install cssmin
pip install pyscss
Flask-Assets extension에서 pyScss컴파일러 사용 설정법

from flask import Flask, render_template
from flask.ext.assets import Environment, Bundle

app = Flask(__name__)

assets = Environment(app)
assets.url = app.static_url_path
scss = Bundle('foo.scss', 'bar.scss', filters='pyscss', output='all.css')
assets.register('scss_all', scss)
And in the template include this:

{% assets "scss_all" %}
{% endassets %}

SCSS file은 debug모드에서도 컴파일 된다.

캐쉬
Flask-Cache : 플라스크에서 캐쉬 사용 하기 쉽게 도와줌.
# Flask-Cache Cache Type
CACHE_TYPE = 'simple' # 개발 시
CACHE_TYPE = 'redis' # 배포 시. redis 서버 구동 필요.
from flask.ext.cache import Cache

app = Flask(__name__)
cache = Cache()
cache.init_app(app, config={'CACHE_TYPE': CACHE_TYPE})

파일 업로드
Flask-Uploads : 파일 업로드 관련 처리를 도와줌.
from flask.ext.uploads import UploadSet
images = UploadSet()
images.__init__('upload', IMAGES)
filename = images.save(files, folder='/images', name='test.')
image_path = images.path(filename)
url = images.url(thumbnail)

텍스트 검색
Flask-WhooshAlchemy : 텍스트 기반 검색을 쉽게 도와줌

오류 추적
flask-exceptional : 오류 추적 서비스인 exceptional를 flask에서 이용 가능하게 도와줌.

전자상거래(e-commerce) [flask용 extension 아님]
stripe : 결제 모듈을 간편하게 시스템에 붙이도록 도와주는 서비스.
satchmoproject : 오픈소스 전자 상점 프레임워크 (satchmo Wiki)
satchless : 프레임워크에 종속적이지 않은 e-commerce용 클래스와 패턴 모음
flamaster : flask용 e-commerce eventing 시스템

Flask에서 JSON 다루기(JSON Handling in Flask)
http://flask.pocoo.org/docs/api/#module-flask.json

import requests
r = requests.get(QUERY_URL)
return r.json
//normal return
return jsonify(username=g.user.username,
email=g.user.email,id=g.user.id)

jsonify a SQLAlchemy result set in Flask
http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask
jsonify의 문제는 object가 자동으로 json화 되지 않는다는 것이다.
serialize를 위해 다음을 모델에 추가 해 준다.


def dump_datetime(value):
"""Deserialize datetime object into string form for JSON processing."""
if value is None:
return None
return [value.strftime("%Y-%m-%d"), value.strftime("%H:%M:%S")]

class Foo(db.Model):
//... SQLAlchemy defs here..
def __init__(self, ...):
//self.foo = ...
pass
@property
def serialize(self):
"""Return object data in easily serializeable format"""
return {
'id' : self.id,
'modified_at': dump_datetime(self.modified_at),
# This is an example how to deal with Many2Many relations
'many2many' : self.serialize_many2many
}
@property
def serialize_many2many(self):
"""
Return object's relations in easily serializeable format.
NB! Calls many2many's serialize property.
"""
return [ item.serialize for item in self.many2many]

뷰에서는 아래처럼 사용한다.

return jsonify(json_list=[i.serialize for i in qryresult.all()])

gunicorn서버 사용 설정.

from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)

if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run()

Blueprint
routing관리에 이용한다.
application/feedback 폴더에 모듈을 넣을 경우.

from flask import Blueprint
mod = Blueprint('root', __name__, url_prefix='') // prefix를 공란으로 두면 root를 의미한다.
mod = Blueprint('feedback', __name__, url_prefix='/feedbacks') // prefix를 채우면 route('/')가 해당 prefix와 같다.
@mod.route('/')

새로운 디렉토리를 만들고 __init__.py파일을 추가해야 import시 인식한다.

모듈을 사용하려면 어플리케이션에서 등록해 준다.

from application.feedback.views import mod as feedbacksModule
app.register_blueprint(feedbacksModule)

파일 여러개 올리기(Uploading multiple files with Flask)
http://stackoverflow.com/questions/11817182/uploading-multiple-files-with-flask


@app.route("/upload", methods=["POST"])
def upload():
uploadedfiles = flask.request.files.getlist("file[]")
print uploadedfiles
return ""

동적으로 생성된 이미지 파일의 url 받기(How to get url for dynamically generated image file?)
http://stackoverflow.com/questions/12034949/flask-how-to-get-url-for-dynamically-generated-image-file

@app.route("/imgs/")
def images(path):
generateimg(path)
fullpath = "./imgs/" + path
resp = flask.makeresponse(open(fullpath).read())
resp.content_type = "image/jpeg"
return resp

mydomain.com/static/test.jpg

from flask import Flask, redirect, url_for

app = Flask(__name__)
@app.route('/')
def index():
generate_img("test.jpg"); #save inside static folder
return '<img src=' + url_for('static',filename='test.jpg') + '>'

Jade
두개의 속성을 지정할 땐 콤마(,)를 잊지 않는다.

script(data-main='js/app', src='js/vendor/require.js')



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

자바 API, Javadoc 만들기 - APIviz[API,Javadoc,Java,자바]

이미지출처 : blogs.sun.com

자바 API, Javadoc 만들기 - APIviz









인수인계를 위해, 어떠한 형태의 문서가 좋을까 고민을 하다가,

내가 참여한 클래스와 메소드들에 대한 설명을 적어서 Javadoc으로 뽑고,

메인페이지에 필요한 사항을 수정하였다.



다이어그램을 자동으로 그려주는 APIviz(http://code.google.com/p/apiviz/)를 사용하였는데,

사용법은 이클립스에서 export시에 다음과 같이 doclet설정을 해주면 된다. (APIviz How to use)
Use Custom Doclet

Doclet Name : org.jboss.apiviz.APIviz

Doclet Class-Path : APIvizPath\jar\apiviz-1.3.0.GA.jar

이후 Vm Option에서 Graphviz 경로 설정 (and Graphviz path setting in VM options)

아래와 같이 필요한 Vm 옵션도 몇가지 추가하였다. (My custom vm options)

VM options
-encoding UTF-8 -charset UTF-8 -docencoding UTF-8  (한글 Javadoc을 만들기 위해[for unicode document])
-J-Dgraphviz.home=GraphvizPath\bin (Graphviz 설정 [Graphviz Setting])
-J-Xmx512m (내보낼 문서의 양이 많을때 메모리 부족 에러가 난다. [Prevent out of memory error during export Javadoc])

Extra Javadoc options
-d OutputPath (내보낼 경로 [Output Path])
-tag author:a:"Author:" (작성자 정보를 문서에 포함시킨다. [include author information in document])


마지막으로 스타일시트는 검색을 하다가,  (I used custom stylesheet in follow link.)

http://applegrew.blogspot.com/2008/05/get-my-javadoc-stylesheet-red-n-black.html 를 사용했다.



그동안 주석을 잘 안달아놔서 꽤 바쁜 작업이 되긴 했지만,

막상 문서작성을 마치고 보니, 꽤 만족스럽다.:D




by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

EclipseRCP 퍼스펙티브 다루기(EclipseRCP perspective handling)[퍼스펙티브,perspective,이클립스 RCP,eclipse RCP]

이미지출처 : www.mobilefish.com

EclipseRCP 퍼스펙티브 다루기(EclipseRCP perspective handling)






등록된 퍼스펙티브 배열 받아오기 (Getting registered perspective array)

IPerspectiveRegistry perspectiveRegistry = window.getWorkbench().getPerspectiveRegistry();
IPerspectiveDescriptor[] perspectiveDescriptors = perspectiveRegistry.getPerspectives();


현재의 퍼스팩티브 받아오기 (Getting current perspective)
WorkbenchWindow.getActivePage().getPerspective();


퍼스펙티브 전환하기 (Changing perspective)
WorkbenchWindow.getActivePage().setPerspective(IPerspectiveDescriptor perspective);




by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

EclipseRCP 체크박스에서 재귀선택 이벤트 (EclipseRCP recursive selection event in checkbox viewer)[checkbox viewer,체크박스,selection event,선택 이벤트,이클립스 RCP,eclipse RCP]

이미지출처 : www.mobilefish.com

EclipseRCP 체크박스에서 재귀선택 이벤트 (EclipseRCP recursive selection event in checkbox viewer)







It’s Tips for CheckboxViewer.



I found bug that throw selection event three times in CheckboxViewer(CheckboxTreeViewer,CheckboxTableViewer).



This bug appear when user click checkbox on selected object.



Then I disable selection as well as “viewer.setSelection(null);";



And I need the checkbox behave likes the radio button.



I implemented it through history clear.





Code:


boolean isHistory;
Object currentObject;
 
public void selectionChanged(SelectionChangedEvent event) {
    if(isHistory) {
      isHistory = false;
      return;
    }
  if (!event.getSelection().isEmpty()) {

      if (event.getSelection() instanceof IStructuredSelection) {

          if(currentObject!= null) {

            if(! currentObject.equals((IStructuredSelection)event.getSelection()).getFirstElement())) {

              isHistory = true;

            viewer.setChecked(currentObject, false);

              viewer.setSelection(new StructuredSelection(currentObject);

              isHistory = false;

              viewer.setSelection(null);

            }

          }

        currentObject = (IStructuredSelection)event.getSelection()).getFirstElement();

            viewer.setChecked(currentObject , !viewer.getChecked(currentObject ));

            viewer.getTable().setSelection(currentObject.index);

          viewer.setSelection(null);

      }

    }

  }



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

EclipseRCP 문제해결 (EclipseRCP Trouble Shooting)[Trouble shooting,이클립스 RCP,eclipse RCP]

이미지출처 : www.mobilefish.com

EclipseRCP 문제해결 (EclipseRCP Trouble Shooting)







Product export errors



Q. I did product exported. But it can not run properly. Why?!



A. I recommend you to confirm ‘Build Configuration’ for missing any folders and files to include in the binary build.



Q. How can I ignore check event in CheckedTableViewer or CheckedTreeViewer?



A. You can use this trick.


Code:



//// ignore Check Event  //

    table = viewer.getTable();

    table.addListener(SWT.Selection,new Listener() {

         public void handleEvent(Event event) {

             if( event.detail == SWT.CHECK ) {

                    event.detail = SWT.NONE;

                    event.type   = SWT.None;

                    event.doit   = false;

                    try {

                      table.setRedraw(false);

                       TableItem item = (TableItem)table.getItem(0);

                       item.setChecked(! item.getChecked() );

                    } finally {

                      table.setRedraw(true);

                    }

             }

         }

      });



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.

EclipseRCP 다른플러그인에서 환경설정 가져오기. (EclipseRCP How to get Preferences from other Plug-ins?)[다른 플러그인 환경가져오기,get preferences,이클립스 RCP,eclipse RCP]

이미지출처 : www.mobilefish.com

EclipseRCP 다른플러그인에서 환경설정 가져오기. (EclipseRCP How to get Preferences from other Plug-ins?)






최신의 이클립스 RCP 어플리케이션에서 Platform.getPlugin("plugin name") 을 사용하지 말라고 권고하기 때문에

Platform.getPlugin("plugin name").getPluginPreferences() 를 이용해서 가져올 수가 없다.



Latest Eclipse RCP Application API not recommended to use Platform.getPlugin("plugin name"). Then we can not get preferences from

Platform.getPlugin("plugin name").getPluginPreferences();



그럼 어떻게 다른 플러그인에서 Preference를 가져오느냐?

How to get Preference from other Plug-ins?

다음을 이용하면 다른 플러그인의 환경을 가져올 수 있다.

You can get Preferences use these.



IEclipsePreferences pref = [each scope what your need.]



new ConfigurationScope().getNode("plugin name");

or

new InstanceScope().getNode("plugin name");




Reference : http://dev.eclipse.org/newslists/news.eclipse.platform/msg72722.html



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    방랑자의 이야기.
    월풍도원에선 기부를 받습니다.