아일랜드 전통 음악과 진한 스타우트 한잔이 생각날 때. SinE.

입구-'Irish pub SinE, Cork'

친구가 추천했던 두 펍 중에 한 곳을 이번에 들렀습니다.

연주 안내-'Irish pub SinE, Cork'

매주 화요일 저녁 아홉 시 반에 아일랜드 전통 곡을 연주하는 펍이에요.

이 층-'Irish pub SinE, Cork'

이 층이 분위기가 아늑하고 좋은데,
연주는 일 층에서 하더라고요.
워낙 유명한 곳이라 그런지 발 디딜 틈 없이 붐볐어요.
사람이 적당히 모이면 흥겹고 좋지만,
제가 갔을 땐 너무 시끌벅적해서 음악도 잘 들리지 않더라고요.

아이리시 전통 곡 연주-'Irish pub The Corner House, Cork'

그래서 맥주 한 잔 마시고 옆집인 골목 집(The Corner House)으로 자리를 옮겼습니다.
여기서도 아일랜드 전통 음악을 연주해요.
자리도 널찍하고 좋았습니다.
코크에서 아일랜드 전통 음악을 들으려면 SinE에!
혹시 너무 붐비면 그 옆집 The Corner House도 좋습니다!

아일랜드에선 젊은이들도 전통 곡 연주를 들으러 펍을 찾습니다.
우리나라라면 전통 음악을 연주한다고 젊은이들이 과연 그곳을 찾아갈까요?
한국에서 '전통' 하면 뭔가 고리타분하고 재미없는 이미지가 떠올라요.
왠지 그건 어르신 전용 같은 느낌입니다.
지금도 이럴진대 아마 우리 세대가 어르신이 된다면 '전통' 문화는 그야말로 감쪽같이 자취를 감추겠지요.

우리나라의 주막에서도 한국 전통 곡을 연주하면 어떨지 한번 상상해 봤습니다.
사물놀이를 실내에서 연주한다면 주막이 너무 비좁게 느껴질 것 같아요.
그리고 악기 구성이 타악기에만 편중되어 좀 아쉽습니다.
그렇다고 악기란 악기를 다 갖춰서 종묘제례악이나 궁중음악을 연주하는 것도 안 어울리지요.
뭐 가끔은 그런 음악에 술잔을 기울이는 것도 괜찮겠지만,
주막이 무슨 돈으로 대규모 악단을 매번 초청하겠어요.
게다가 주막에서 연주하기 좋은 국악이 딱 떠오르는 게 없습니다.
제가 들어서 좀 신나는 음악이라면 취타, 타령·군악과 민요등이 있는데,
이걸 주막에서 연주한다고 생각하면 좀 아쉬워요.
시나위와 사물놀이에 쓰이는 악기를 적절히 버무려서 연주한다면 참 멋질 텐데 말이지요.
실력 좋은 음악가분들이 3~4인 악단용 흥겨운 국악을 풍성히 작곡해 주시면 좋겠어요. :D
(제가 그런 실력이 있다면 당장에라도 뛰어들 텐데 아쉽네요. 하하)

외국에 한국 숙소나 식당은 많은데 주막은 못 봤어요.
뭐 코리아타운이 형성될 정도라면 주막이 한두 곳쯤은 있겠지만 말이에요.
아이리시 펍은 전 세계에 퍼져있습니다.
한국 전통 술 참 맛 좋아요.
게다가 안주도 끝내주지요.
여기에 흥겨운 음악까지 받쳐준다면 전 세계가 주막에 열광 할 겁니다.
그러려면 우선 한국에서 이런 문화가 자연스럽게 퍼저야 합니다.
“헤이 맨! 오늘 주막(Jumak)에서 한잔 어때?”
어디서나 이런 말이 자연스레 들릴 날이 오길 고대합니다.



by


Tags : , , , , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

무더운 여름. 시원한 러시아에서. 체르노빌 다이어리.

chernobyl

오랜만에 극장에 갔습니다.
스파이더맨이 개봉하는 날인데, 별로 내키지가 않더라고요.
아이스 에이지 4와 체르노빌 다이어리 중에서 뭘 볼까 하다가 이 영화를 골랐습니다.
즉흥적인 선택인지라 장르가 뭔지도 몰랐어요.
광고가 끝나고 제목이 딱 나타날 때 알아챘습니다.
‘어두운 글씨가 여기저기 구멍이 나 있는 게 아무래도 공포·스릴러인가보다.’
저는 공포 영화를 즐겨보지 않습니다.
왜냐면...
무섭잖아요?
게다가 전 깜짝깜짝 놀라기도 잘 놀라고 말이지요.
그런데 웬걸.
이 영화를 보는 내내 포레스트 검프가 생각납니다.
‘뛰어 포레스트. 뛰라고!’
열심히 달리는 장면이 많아서 그랬나 봐요.

영화에서 흥미로웠던 건,
여행 중에 생길법한 일화를 소재로 삼았단 건데요.
체르노빌처럼 인적이 드문 곳에서 길을 잃는다면,
야생 동물의 습격을 받을 수도 있겠다는 생각이 들었습니다.
실제로 요즘 체르노빌엔 사나운 짐승도 많이 산다더라고요.
혹시 오지에 가게 된다면 마음을 단디 먹어야겠습니다.



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

컴퓨터 앞에 오래 앉아계시나요? 포모도로 테크닉으로 건강을 챙겨 봅시다.

Pomodoro technique

저는 컴퓨터 앞에 앉아 지내는 시간이 많습니다.
오랜 시간 앉아 있으면 어깨도 뻐근하고 온몸이 삐걱거려요.
'아무래도 스트레칭을 자주 해야겠어.'
스트레칭용 타이머를 찾다가 포모도로 테크닉을 발견했습니다.
토마토 모양만 봐도 건강해 보이지요? ^^
한 세트는 네 번의 타이머로 구성됩니다.
25분이 한 포모도로에요.
한 포모도로가 끝나면 오 분 정도의 짧은 휴식을 하고,
한 세트가 끝나면 십오 분 가량 좀 긴 휴식 시간을 가지는 시간 관리 방법입니다.
TO-DO 목록을 작성하고 포모도로 타이머가 돌아가는 동안 리스트를 지워나가며 일을 하는 것이죠.
저는 TO-DO 목록 작성을 별로 선호하는 편이 아니에요.
리스트로 만들어야 할 정도로 중요한 거면 굳이 리스트를 만들지 않고 당장 하면 되고,
별 중요한 게 아니라면 목록을 만들 필요도 없으니까요.
뭘 하다가 중간에 다른 일로 넘어가야 할 때나 가끔 할 일 목록을 이용합니다.
그래서 전 스트레칭 시간 알리미로 포모도로 타이머를 쓰는데요.
확실히 피로가 덜 합니다.
일단 앉으면 시계를 잘 보지 않는 편이라, 이 타이머가 아주 유용해요.

사용한 지 삼 주 정도 되었는데, 썩 만족스럽습니다.
처음엔 25분이 너무 금방 지나가는 듯 했는데,
쓰다 보니 한 포모도로가 그리 짧지 않습니다.
몸을 풀어주지 않고 계속 앉아있으면 몸이 피로하고 일이 손에 잘 안 잡히잖아요?
포모도로 타이머를 이용해 쉬는 시간마다 스트레칭을 해 주니,
컴퓨터 앞에 앉아있는 동안 집중이 더 잘돼요.
IT 업종 등 하루 종일 모니터를 바라보며 앉아있는 분들은 한번 이용해 보세요. :D



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

자주 쓰는 엑셀 함수 정리.


엑셀, 문자열 다루기 - 문자열 함수 (텍스트 함수)

  • CHAR - 코드 번호에 해당하는 문자를 반환합니다.
  • CODE - 텍스트 문자열의 첫 문자를 나타내는 코드 값(숫자)을 반환합니다.
  • CONCATENATE - 여러 텍스트 항목을 한 텍스트 항목으로 조인합니다.
  • EXACT - 두 텍스트 값이 동일한지 검사합니다.
  • FIND - 텍스트 값에서 다른 텍스트 값을 찾습니다(대/소문자 구분).
  • LEFT - 텍스트 값에서 맨 왼쪽의 문자를 반환합니다.
  • LEN - 텍스트 문자열의 문자 수를 반환합니다.
  • LOWER - 텍스트를 소문자로 변환합니다.
  • MID - 텍스트 문자열의 지정한 위치로부터 지정한 개수의 문자를 표시합니다.
  • PROPER - 텍스트 값에 있는 각 단어의 첫 글자를 대문자로 바꿉니다.
  • REPLACE - 텍스트 내의 문자를 바꿉니다.
  • REPT - 텍스트를 지정한 횟수만큼 반복합니다.
  • RIGHT - 텍스트 값에서 맨 오른쪽의 문자를 반환합니다.
  • SEARCH - 텍스트 값에서 다른 텍스트 값을 찾습니다(대/소문자 구분 안 함)
  • SUBSTITUTE - 텍스트 문자열에서 기존 텍스트를 새 텍스트로 바꿉니다.
  • T - 인수를 텍스트로 변환합니다.
  • TEXT - 숫자 표시 형식을 지정하고 텍스트로 변환합니다.
  • TRIM - 텍스트에서 공백을 제거합니다.
  • UPPER - 텍스트를 대문자로 변환합니다.
  • VALUE - 텍스트 인수를 숫자로 변환합니다.
  • CONCATENATE (문자열1,문자열2,...)
  • REPLACE(문자열, 시작위치, 바꿀 문자수, 바꿀 문자열)
  • SUBSTITUTE(문자열, 찾을 문자열, 바꿀 문자열)
엑셀, 문자열 다루기 - 문자열 함수 (텍스트 함수) [강동의별님의 블로그]

엑셀, 문자열 다루기 - 문자열 함수 (텍스트 함수)

  • 상대참조(A1 형식) : 셀의 변위에 따라 상대적으로 참조셀의 위치도 변하는 형식.
  • 절대참조($A$1 형식) : 셀의 변위에 상관없이 참조셀이 고정적으로 정해진 형식.
엑셀 절대참조,상대참조 - 기본 중의 기본 [강동의별님의 블로그]

컬럼 합치기

=A1&" "&B1

텍스트 추출하여 날짜/시간 형식으로 변환

=DATE(LEFT(A1,4),MID(A1,5,2),MID(A1,7,2))+TIME(MID(A1,10,2),RIGHT(A1,2),0)

조건절에 만족하면 갯수 세기

=IF(COUNTIF(Sheet1!$A$2:$A$6,Sheet2!A2)=1,1,0)

원하는 범위에서 값 찾아 바꾸기

VLOOKUP(lookup_value,table_array,col_index_num,range_lookup)
=vlookup(B1,sheet1!$C$1:$E$13, 3,false),0)


원하는 범위에서 여러 컬럼 값 찾아 바꾸기

=index(Sheet1!$D$1:$D$44,match(A1&B1,Sheet1!$A$1:$A$44&Sheet1!$B$1:$B$44,0))
Sheet1!$A$1:$A$44&Sheet1!$B$1:$B$44 범위에서 A1&B1값을 찾으면 Sheet1!$D$1:$D$44값을 컬럼에 채운다.


함수를 적용시키려면 CTRL+ENTER
배열 수식{}을 적용시키려면 CTRL+SHIFT+ENTER

엑셀 함수 참조 사이트

Contextures - Excel Tips and Excel Tutorials



by


Tags : , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

바다가 아름다운 작은 시골 마을. 밴트리.

아침 일찍 집에서 나와 버스터미널로 갑니다.
일기예보에선 날씨가 아주 화창하다고 허세를 부리지만,
그런 격장지계에 넘어가 홀딱 젖기는 싫어 우비도 챙겨 나왔지요.
코크 버스터미널에서 236번 버스를 타고 한참을 갑니다.
조그만 마을 몇을 거쳐 밴트리로 가는 길.
갑자기 먹구름이 몰려와 비를 쏟아 부었으나,
목적지에 도착하자 날씨가 갭니다.
운이 좋아요.
근데 일요일이라 그런지 여행자 정보 센터는 문을 닫았네요.
뭐 조그마한 동네라 굳이 지도가 필요 없긴 해요.
우선 마을을 한 바퀴 쓱 돌아봅니다.

멀리 보이는 놀이기구-'Bantry, Co Cork Ireland'

저 멀리 놀이기구가 보이네요.
집 근처의 월미랜드가 생각납니다.
어릴 때 가서 많이 놀았는데 말이에요.
그곳을 찾은 지도 오래되었군요.
한국에 가면 한번 들러봐야겠습니다.

밴트리 하우스-'Bantry, Co Cork Ireland'

바닷가를 따라 쭉 걸어가면 정원을 잘 가꿔놓은 밴트리 하우스가 보입니다.
아기자기해요.
100계단을 올라가 내려다보는 바닷가 풍경이 썩 괜찮습니다.
밴트리 하우스엔 조그마한 카페도 하나 있는데,
음료와 간식거리를 팔아요.
비가 많이 내린다면, 카페 앞 테라스의 푹신한 의자에 앉아 잠시 비를 피하는 것도 좋겠지요.

수제 다크 초콜릿-'Bantry, Co Cork Ireland'

이 카페에서 파는 초콜릿이 꽤 맛납니다.
카카오가 70%라서 그리 진하진 않지만 달짝지근한 게 괜찮아요.

맑은 날씨의 바닷가-'Bantry, Co Cork Ireland'

자. 이제 밴트리 하우스를 나와 해변을 따라 쭉 걷습니다.
아.
이런 날씨라니.
하늘만 바라봐도 기분이 좋네요.

온통 푸른 풍경-'Bantry, Co Cork Ireland'

바닷가에 앉아 짭짤한 공기를 마음껏 들이마셨습니다.
물수제비를 뜨기 좋은 납작한 돌멩이가 여럿 보이는군요.
적당한 녀석을 골라 던져 보았지만 한 두 번 튀기고 물속으로 가라앉습니다.
푸른 바다가 그 돌을 감싸고 어디론가 데려가겠지요?
저도 이곳의 푸른 기운에 이끌려 이리저리 발걸음을 옮겼습니다.
아름다운 하루에요.



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Web application development References


ISO-639-1


Official languages of the United Nations

  • Arabic
  • Chinese (Mandarin)
  • English
  • French
  • Russian
  • Spanish

CLDR

Unicode Common Locale Data Repository

터미널 한글 설정

windows cmd - chcp 65001
linux shell - export LC_ALL=ko_KR.UTF-8


구글 맵스 지도 검색

https://maps.google.com/?q=이름@위도,경도

구글 정의 검색

define:something

Protocol SPDY

http://www.chromium.org/spdy

MongoDB

사용자추가 스키마생성 DB삭제

mongod 를 기동할 때는 --auth 옵션을 추가해야 함
mongoDB는 system영역 내에서 admin이라는 DB관리를 위한 스키마를 가짐
>use admin // admin DB 사용
>db.addUser('name','pswd') // 사용자 추가
>use newDB => 해당 디비가 없으면, 새로운 디비를 생성함
   mysql의 스키마 생성과 같음
>db.collectionName.drop() => 해당 collection을 삭제함
   mysql의 DROP TABLE과 같음

Mongodb eclipse

log path configuration

"C:\data\mongodb-xxxxxxxxx\bin\mongod" --service  --logpath  c:\data\test.log

import

mongoimport --host localhost --db myapp_development --collection my_collection --type csv --file C:\dev\data\test.csv --headerline --upsert

regex

mongodb regex = '^[work|accus*|planet]'
MongoDB can only use indexes on Regular Expression searches that are front (^) anchored.
RegEx searches that front-anchor and then use a wildcard query like .* will use the index for as much of the un-wildcarded area as it can before scanning --- i.e., ^foo.* will run a partial scan.


Mysql

mysql backup and restore


mysqldump -uUSER -pPASSWORD -hHOST DB > ./filename.sql
mysql -uUSER -pPASSWORD -hHOST DB < ./filename.sql

MySQL index

What should be indexed?
–All attributes where you JOIN
–All attributes where you filter (WHERE)
–All attributes where you ORDER or GROUP BY
–All attributes where you want to do an Index Scaninstead of a Table scan.
–NOT on attributes with an evenly distributed lowcardinality.
•How should be indexed?
–Indexes can only be used from left to right.
–Keep them short.
–Compound indexes: INDEX(a, b).
–Prefixed indexes: INDEX(a, b(10)).
–Do not function-cover indexed attributes

http://www.scribd.com/doc/80792061/MySQL-Performance-Tuning

MySQL Date and Time Functions


Mysql 동일 테이블에서 여러 필드 값의 합 쿼리

//쿼리1 보다 쿼리2가 두 배 이상 빠르다. 단, 하나의 칼럼 갯수를 구할 땐 where절과 count(*)를 쓰는 것이 더 빠르다.
//쿼리1
select sum(cnt) from (
    select count(*) as cnt from `my_table` WHERE `field_x` =1
    union all
    select count(*) as cnt from `my_table` WHERE `field_y` =1
    union all
    select count(*) as cnt from `my_table` WHERE `field_z` =1
) as cnt_all
//쿼리2
SELECT
(SUM(IF(`field_x` = 1,1,0)) +   
    SUM(IF(`field_y` = 1,1,0)) +
    SUM(IF(`field_z` = 1,1,0))) as cnt_all
FROM `my_table`
WHERE 1


firefox - keyword.url

http://www.google.co.kr/search?num=50&hl=ko&lr=&newwindow=1&tbo=1&as_qdr=all&aq=f&aqi=&aql=&oq=&gs_rfai=&ie=UTF-8&oe=UTF-8&sourceid=navclient&gfns=1&q=

리눅스 crontab

crontab -l

CSS FONT BASE-64

/* Fonts as files */
@font-face {
    font-family: 'MyFontFamily';
    src: url('myfont-webfont.eot?') format('eot'),
         url('myfont-webfont.woff') format('woff'),
         url('myfont-webfont.ttf')  format('truetype'),
         url('myfont-webfont.svg#svgFontName') format('svg');
    }
/* Fonts as data uris */
@font-face {
    font-family: 'MyFontFamily';
    src: url('myfont-webfont.eot?') format('embedded-opentype');
    }
   
@font-face {
    font-family: 'MyFontFamily';
         url(data:font/truetype;charset=utf-8;base64,BASE64_ENCODED_DATA_HERE)  format('truetype'),
         url(data:font/woff;charset=utf-8;base64,BASE64_ENCODED_DATA_HERE)  format('woff'),
         url('myfont-webfont.svg#svgFontName') format('svg');
    }


CSS Sticky windows

    .outer {
        width:200px;
        height:600px;
        background-color:red;
        margin:0 auto;
    }
    .inner {
        width:50px;
        border:1px solid white;
        position:fixed;
    }
 


Insert the word (image) into the alt text of an image that hasn’t loaded In Firefox

img:after   { content:" (image)"; }
img::after  { content:" (image)"; } /* New CSS3 standard notation */


FYI

References and Articles

빠른 웹 개발

도구


출처

  • 직접 작성
  • google 검색



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Ruby Gems Cheat Sheet


GEM 설정

gem environment
set GEM_PATH = D:\dev\ruby192\lib\ruby\gems\1.9.1\gems
gem update --system
gem uninstall gemname
bundle update
(vendor 폴더에 bundle 설치하기)
bundle install --path vendor/bundle


devise

Controller filters and helpers

Devise will create some helpers to use inside your controllers and views. To set up a controller with user authentication, just add this before_filter:
before_filter :authenticate_user!
To verify if a user is signed in, use the following helper:
user_signed_in?
For the current signed-in user, this helper is available:
current_user
You can access the session for this scope:
user_session
Callbacks
    after_set_user
    after_authentication
    before_failure
    before_logout
    Warden::Manager.after_authentication do |user,auth,opts|
        user.last_login = Time.now
    end
   

generator

devise g view with haml
rails g devise_views -t=haml

OmniAuth

Add :password => Devise.friendly_token[0,20] when creating a new user from facebook omniauth.

Passwords Encrypt manually


Assuming you have a mysql database with a "users" table and a "password" column And an ActiveRecord model class called "user" that is hooked up to devise
Create an ActiveRecord model class in your app app/models/old_user.rb
OldUser < ActiveRecord::Base
  set_table :users
  establish_connection :database => "old_database", :user => "old user", :adapter => "mysql"
end
then create a rake task: app/lib/tasks/migrate_users.rake
task :migrate_users => :environment do
  OldUser.find_each do |old_user|
    u = User.new(:email => old_user.email, :password => old_user.password, :password_confirmation => old_user.password);
    #if your using confirmation
    u.skip_confirmation!
    u.save!
  end
end
Modify as necessary (make sure you're saving any app-specific user attributes)
Then$ rake migrate_users
   
Good news and bad news.
Good news:
The following works to create your user's password manually.
 pepper = nil
 cost = 10
 encrypted_password = ::BCrypt::Password.create("#{password}#{pepper}", :cost => cost).to_s
You can find your pepper and cost in your devise initializer. This method was confirmed using Devise's "valid_password?" method.
Bad news:
The entire reason I was trying to avoid "User.new(password: password).encrypted_password" was because of speed. It's terribly slow. With all my other pieces of my import task, I've intentionally avoided this.
But as it turns out, the major cost here is not instantiating a User object -- but BCrypt itself. There is very little noticeable speed boost when using BCrypt directly because it's intentionally designed to be slow.
My final answer: suck it up, run the rake script, go find a beverage.

mailer locale configuration

-ActionMailer::Base.default_url_options[:locale] = I18n.locale


Simple_form

<%= simple_form_for(@user, :builder => CustomBuilder) do |f| %>
  <%= f.input :name %>
<% end %>


Client side validations

Client side validations Registering own form builder
https://github.com/bcardarella/client_side_validations/wiki/Registering-your-own-custom-form-builder


Client MVC

Spine

Important is only that the public directory of the application is specified
as domainroot in Confixx. If the domain is called Passenger will start automatically.."
rails g spine:model Card text is_private order user_id card_type
rails g spine:controller Cards
rails g spine:scaffold card text is_private order user_id card_type
rails g spine:model Organization title description url image admins members followers
rails g spine:controller Organizations
rails g spine:scaffold organization title description url image admins members followers
var card = App.Card.create({ 
  is_private: true,
  order: 0,
  card_type: 'Reason',
  text: 'Spine & Rails, sitting in a tree!'
});
straightforward way to do that without extending Spine Model's
to allow for instances to be added in memory without syncing
Ajax.disable -> saveStuff()
Model.refresh()
extends
Contact.extend(Spine.Model.Ajax);
Contact.extend({
url: '/users/'
});
'/': ->
    if AuthenticatedUser
         @controller = new OtherController
         @replace @controller.render()
    else
         @controller = new LoginController
         @replace @controller.render()
http://spinejs.com/docs/controller_patterns         
         


Compass

compass init rails D:/dev/workspace/baksisi
compass init rails -r html5-boilerplate -u html5-boilerplate --syntax sass --force
css와 javascript를 asset 폴더로 옮겨준다. rails.js는 제외 (jquery_ujs와 동일하다)


Geo_location

https://github.com/chrisyour/geo_location
http://www.maxmind.com/app/geolitecountry


Mongoid id 변경하기

http://blog.joshdzielak.com/blog/2011/12/24/tame-the-mongoid-id-field-in-your-rails-and-backbone-js-app/
http://lostechies.com/derickbailey/2011/06/17/making-mongoid-play-nice-with-backbone-js/


Mongoid Follow unfollow

class User
  include Mongoid::Document
  field :name, type: String
  has_and_belongs_to_many :following, class_name: 'User', inverse_of: :followers, autosave: true
  has_and_belongs_to_many :followers, class_name: 'User', inverse_of: :following
  def follow!(user)
    if self.id != user.id && !self.following.include?(user)
      self.following << user
    end
  end
  def unfollow!(user)
    !self.following.include?(user)
    self.following.delete(user)
  end    
end
relation_ids instead? that is self.member_count = self.member_ids.size
self.challenged.where(_id: event.id).destroy_all
def unchallenge!(announce)
  self.announcements.destroy_all( conditions: { _id: announce.id })
  self.save!
end
Finally I successfully deleted the relation using self.challenged_ids.delete(event.id)
validates_inclusion_of :foo, in: [['foo'], ['bar']]


Mongoid polymorphic behaviour

When a child embedded document can belong to more than one type of parent document, you can tell Mongoid to support this by adding the as option to the definition on the parents, and the polymorphic option on the child.
class Doctor
  include Mongoid::Document
  embeds_one :name, as: :namable
end
class Nurse
  include Mongoid::Document
  embeds_one :name, as: :namable
end
class Name
  include Mongoid::Document
  embedded_in :namable, polymorphic: true
end


TEST

Cucumber

rails g cucumber:install ?capybara ?rspec
  ruby script/rails generate cucumber:feature user email:string password:string confirm_password:string name:string nickname:string gender:integer location_name:string location:integer email_is_priavate:boolean name_is_private:boolean danted:boolean description:string
  ruby script/rails generate scaffold post title:string body:text published:boolean
  rake db:migrate
  rake cucumber


Cucumber Errors Handling

If SystemStackError: stack level too deep 
Then add gem "rspec", ">= 2.6.0.rc2", :group => [:development, :test] to Gemfile


Cucumber & Capybara Ajax

sleep second
page.driver.browser.execute_script %Q{ $('.ui-menu-item a:contains("#{link_text}")').trigger("mouseenter").click(); }
Clicking any element with Cucumber and Capybara
class Capybara::XPath
  class << self
    def element(locator)
      append("//*[normalize-space(text())=#{s(locator)}]")
    end
  end
end
When 'I click "$locator"' do |locator|
  msg = "No element found with the content of '#{locator}'"
  locate(:xpath, Capybara::XPath.element(locator), msg).click
end
The step looks for any element with the given text. Here it is in use:
Scenario: Creating an item
  Given I am signed in as "brandon@example.com"
   When I click "Add to your list"
    And I fill in "Description" with "blog about clicking any element"
    And I press enter
   Then I should see "The item was added to your list"
    And I should see "blog about clicking any element"
   


Cucumber Capybara

selenium chrome driver
https://github.com/jnicklas/capybara
http://code.google.com/p/chromium/downloads/list
http://code.google.com/p/selenium/wiki/ChromeDriver#Overriding_the_Chrome_binary_location
Capybara.register_driver :selenium_with_firebug do |app|
  Capybara::Driver::Selenium
  profile = Selenium::WebDriver::Firefox::Profile.new
  profile.add_extension(File.expand_path("features/support/firebug-1.6.0-fx.xpi"))
  Capybara::Driver::Selenium.new(app, { :browser => :firefox, :profile => profile })
end
Before("@selenium_with_firebug") do
  Capybara.current_driver = :selenium_with_firebug
end


I18n

I18n-js initialize

layout/application.html.haml
- html_tag :class => 'no-js', :lang => "#{I18n.locale}"
applcation.js
I18n.default_locale = "en"
I18n.locale = $($("html")[0]).prop("lang")
I18n.fallbacks = true


Media - Flickraw

    flickr.upload_photo(params[:photo].tempfile.path)


Gem Trouble shooting

Q. `require': no such file to load -- thin (LoadError)
A. => Add gem 'thin' to Gemfile


Rails Performance

  • Curb for Http (libcurl)
  • Yajl, the fastest JSON library.
  • excon #=> faster http
  • Nokogiri, the fastest XML library.
  • Snappy, super fast compression tool by google.
  • fast_xs
  • Memcache. (libmemcached)
  • use Ree Garbage Collector

Fastest Server

  • Unicorn
  • Thin

Profiling Tools

  • NewRelic - Monitoring Tool (Commercial)
  • Ganglia - Monitoring Tool (OpenSource)
  • Cloudflare - Performance & Security
  • rack-perftools

Rack-bug

1. Install rack-bug (branch rails3) as plugin
cd vendor/plugins
git clone -b rails3 https://github.com/brynary/rack-bug.git
If you want to you it as gem then add following line into Gemfile
gem 'rack-bug', :git => 'https://github.com/brynary/rack-bug.git', :branch => 'rails3'
2. Replace the code from file actionview_extension.rb
which is avilable in vendor/plugins/rack-bug/lib/rack/bug/panels/templates_panel/ as specified in bug of rack_bug repository
if defined?(ActionView) && defined?(ActionView::Template)
ActionView::Template.class_eval do
def render_with_rack_bug(*args, &block)
Rack::Bug::TemplatesPanel.record(virtual_path) do
render_without_rack_bug(*args, &block)
end
end
alias_method_chain :render, :rack_bug
end
end
If you are using gem override the specified file in some way
3. Add following lines into your config.ru
require 'rack/bug'
use Rack::Bug, :secret_key => "someverylongandveryhardtoguesspreferablyrandomstring"
run myapp
4. Start your server and access the URL http://your_app/__rack_bug__/bookmarklet.html
and enter the password.
http://blog.railsupgrade.com/2011/04/configure-rack-bug-for-rails-3.html


출처



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Ruby on Rails Cheat Sheet


rails 데이터 타입

:string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean

Rails Mimetype   

"./."                      => :all
"text/plain"               => :text
"text/html"                => :html
"application/xhtml+xml"    => :html
"text/javascript"          => :js
"application/javascript"   => :js
"application/x-javascript" => :js
"text/calendar"            => :ics  
"text/csv"                 => :csv  
"application/xml"          => :xml
"text/xml"                 => :xml
"application/x-xml"        => :xml
"text/yaml"                => :yaml
"application/x-yaml"       => :yaml
"application/rss+xml"      => :rss  
"application/atom+xml"     => :atom 
"application/json"         => :json
"text/x-json"              => :json

bundle asset precompile

bundle exec rake assets:precompile RAILS_ENV="production"
rake assets:clean< add below code if you want development environment with out precompile config.serve.static.assets = false application.rb use Bundler.require(:default, :assets, Rails.env) instead of Bundler.require(*Rails.groups(:assets => %w(development test)))

compile assets locally

Put below into development.rb
config.assets.prefix = "/temp-assets"
Also put below into application.rb
config.assets.initialize.on.precompile = false

rails logger

Rails.logger.info "My info message"
Rails.logger.debug "My debugging message"
Rails.logger.warn "My warning message"

Environment Log level

config.log_level = :debug, :info, :warn, :error, and :fatal

Validation text length CR filter

before.validation :replace.cr
  protected
  def replace.cr
    if self.description.changed?
      self.description.gsub!(/\r\n?/, "\n")
    end
  end

validation locale


// config/locales/en.yml
en:
  activerecord:
    attributes:
      user:
        email: "E-mail address"
    errors:
      models:
        user:
          attributes:
            email:
              blank: "is required"
If you are using mongoid, replace activerecord: with mongoid:

Validate associated

The answer to this turned out to be rather simple. On the parent model, you simply explicitly declare that you want the associated children validated.
parent.rb
validates_associated :children

Validate if persisted? or new_record?

validates.uniqueness.of :nickname, :message => I18n.t("user.already.taken"), :if => :new.record?
validates.uniqueness.of :nickname, :message => I18n.t("user.already_taken"), :unless => :persisted?

Session Store in rails 3

Use the database for sessions instead of the cookie-based default, which shouldn't be used to store highly confidential information
Create the session table with
rake db:sessions:create
Run the migration
rake db:migrate
Make sure you also tell rails to use ActiveRecord to manage your sessions too.
Rails 3
config/initializers/session.store.rb:
Rails.application.config.session.store :active.record.store

DB Migrate Production

rake db:migrate RAILS_ENV="production"

get rails environment

Rails.env
env["SERVER_NAME"]

rails template

rake print --silent RECIPES=jquery,haml,rspec,cucumber,guard,mongoid,action.mailer,devise,add.user,home.page,home.page.users,seed.database,users.page,css.setup,application.layout,html5,navigation,cleanup,ban.spiders,extras,git,compass,omniauth,omniauth.email,backbone > ~/Desktop/backbone.template.txt
Could you please run it again using the "-T -O -J" flags? As in
rails new template_test -m https://github.com/fortuity/rails3-application-templates/raw/master/rails3-mongoid-devise-template.rb -T -O -J
http://blog.dominicsayers.com/2011/08/16/howto-use-a-rails-template-from-github-on-windows/

thin start

D:\dev\ruby192\bin\ruby.exe -e $stdout.sync=true;$stderr.sync=true;load($0=ARGV.shift) D:/dev/workspace/baksisi/script/rails server thin -b 127.0.0.1 -p 3002 -e development
ruby ./script/rails server thin -b smoke-free-online.de -p 3000 -e development -d
thin start

Middle Man

"server" was called incorrectly. Call as "middleman server [-p 4567] [-e development]".
"middleman server [-p 4567] [-e development]" instead of "middleman server -p 4567 -e development

DB migration

Rails g migration change.data.type.for.table_column

I18n

locale join

config/application.rb
config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '.*', '..{rb,yml}')]

locale path

routes.rb
  match '/:locale' => "home#index"
  root :to => "home#index"
  scope "/:locale" do   
    controller :models do
      something
    end
    resources :models, :only => :show
ApplicationController
  def default.url.options(options = {})
    options.merge!({:locale => I18n.locale})
  end   

Localize

I18n.l Time.now, :format => :short,  :locale => :"ko"

Pluralization

ko:
  pears:
    zero: ko.zero
    one: ko.one
    few: ko.few
    other: ko.other

generate rake tasks

rails g task namespace task1 task2
rake -T | grep namespace

세션 저장

config.session.store :cookie.store, :key => '.baksisi.session', :domain => :all
environment.rb 메일러에 레이아웃을 지정하고 싶다면.
DeviseMailer.layout "OMG"

show routes

rake routes

SASS

config/application.rb:
config.generators.stylesheet_engine = :sass
sass-convert style.sass style.scss

Trouble Shootings

uninitialized constant

file name confirm (if file name capital, it can be occurred.)

guard-livereload error

gem install eventmachine --pre 

open-uri.rb file in C:/Ruby1.9.2/lib/ruby/1.9.1/ (of course your path might be different).

http.verify.mode = options[:ssl.verify.mode] || OpenSSL::SSL::VERIFY.NONE

[ERROR] V8 is no longer usable

ulimit -v unlimited  

CSV Data Handling

http://www.ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV.html

get action information at view

    params[:action]

HAML

rails helper using haml
 
def section(name)
haml.tag(:div, :class => 'section') do
  haml.tag(:h2, name)
  haml.tag(:p, :class => 'section.content') do
    yield
  end
end
end
      
def content.box
  haml.tag :div, :class => "holder" do
    haml.tag :div, :class => "top"
    haml.tag :div, :class => "content" do
      yield
    haml.tag :div, :class => "bottom"
  end
end
and in haml
%html
  %head
  %body
    Maybee some content here.
    - content.box do
      Content that goes in the content_box like news or stuff      
     
fields_for with index
<% @questions.each.with.index do |question,index| %>
    <% f.fields.for :questions, question do |fq| %> 
        # here you have both the 'question' object and the current 'index'
    <% end %>
<% end %>
It’s also possible to specify the instance to be used:
<%= form.for @person do |person.form| %>
...
<% @person.projects.each do |project| %>
  <% if project.active? %>
    <%= person.form.fields.for :projects, project do |project.fields| %>
      Name: <%= project.fields.text_field :name %>
    <% end %>
  <% end %>
<% end %>
<% end %>     

Rails Response

namespace "api" do
  resources :regions, :defaults => { :format => 'xml' }
end
Then you should be able to have the following work for your controller methods:
class Api::RegionsController < ApplicationController
  respond.to :xml, :json
  def index
    respond.with(@regions = Region.all)
  end
end
rescue.from  ActionController::MissingFile do |e|
  # User's browser probably wont display this
  # Content-Type is application/x-shockwave-flash
  render :file => File.join(Rails.public.path, '404.html'), :status => 404
end

show details or stream video

def show
  @media = Media.find params[:id]
  respond.to do |format|
    format.html
    format.flv { send.file @media.path, :disposition => 'inline' }
  end
end
render :file => File.join(Rails.public.path, '404.html'), :status => 404, :content.type => 'text/html'

render with variable

render :partial => "my/conejo", :locals => {:my.val => something}
render "my/liebre", :my.val => something

scope

default_scope order('id DESC')
Model.reorder('')
Model.unscoped

render an other action in the controller, in js.

  render 'result', :id => @item.id, :format => :js
 

layout xhr? 

  class ApplicationController < ActionController::Base
  layout proc{|c| c.request.xhr? ? false : "application" }
  end
  layout :layout.xhr?
  def layout.xhr?
    request.xhr? ? false : 'application'
  end
 

AJAX Performance stale? and touch


 def show
    @list_item = @list.list_items.find( params[ :id ] )
    if stale?( :etag => @list_item, :last_modified => @list_item.updated_at.utc, :public => true )
      respond_with( @list_item )
    end
  end
  Also instead of the update_list method being called from after_save/destroy you can pass :touch => true to the belongs_to association which will do the same

AJAX Handler - ?xhr

respond_with( @something, :layout => !request.xhr? )
or
respond_to do |wants|
  wants.html do
    if request.xhr?
      render :partial => "items"
    else
      render
    end
  end
end

Asset

exist

YourApp::Application.assets.find_asset("#{asset}.file").nil?

### pathname

<YourAppName>::Application.assets.find_asset('Rails.png').pathname

absolute asset_path in view using helper

"#{request.protocol}#{request.host.with.port}#{asset.path('person/gravatar.default.png')}"
"#{request.scheme}://#{request.host.with.port}#{request.script_name}"

Mailer

config

environment/production.rb
  config.action.mailer.default.url.options = {:host => 'localhost:3000',:locale =>I18n.locale}
  config.action.mailer.smtp.settings = {
    :address              => "server.addr",
    :port                 => 587,
    :domain               => "sever.domain",
    :user.name            => "user.name",
    :password             => "user.password",
    :authentication       => "plain",
    :enable.starttls.auto => true
  } 
  config.action.mailer.delivery.method = :smtp
  config.action.mailer.perform.deliveries = true
  config.action.mailer.raise.delivery.errors = false
  config.action.mailer.default :charset => "utf-8"

inline attachement

in mailer

attachments.inline['blank'] = {
    :data => File.read("#{Rails.root.to.s + '/app/assets/images/blank.png'}"),
    :mime.type => "image/png",
    :encoding => "base64"
}

in view

if @offer.image.nil?
  = image.tag( attachments['blank'].url, :id => 'attachement.image', :width => "400", :height => "400")
 

validates in I18n

%{attribute} - field name
%{model} - model name 
%{count} - count


rescue log

begin
  ...some code...
rescue Exception => e
  logger.error e.message
 

Ruby

Iterate

a.each.with.index do |item, index|
  puts item, b[index]
end
array.each.slice(3) do |elements|
  fire.the_event
end

Timezone

in client (js):
function set.time.zone.offset() {
    var current.time = new Date();
    $.cookie('time.zone', current.time.getTimezoneOffset());
}
in Application Controller:
before.filter :set.timezone
def set.timezone 
 min = request.cookies["time.zone"].to_i
 Time.zone = ActiveSupport::TimeZone[-min.minutes]
end

DateTime format

  %a - The abbreviated weekday name (Sun)
&nbsp; %A - The&nbsp; full&nbsp; weekday&nbsp; name (Sunday)
  %b - The abbreviated month name (Jan)
&nbsp; %B - The&nbsp; full&nbsp; month&nbsp; name (January)
  %c - The preferred local date and time representation
  %d - Day of the month (01..31)
  %H - Hour of the day, 24-hour clock (00..23)
  %I - Hour of the day, 12-hour clock (01..12)
  %j - Day of the year (001..366)
  %m - Month of the year (01..12)
  %M - Minute of the hour (00..59)
  %p - Meridian indicator (AM&nbsp; or&nbsp;PM)
  %S - Second of the minute (00..60)
  %U - Week  number  of the current year,
          starting with the first Sunday as the first
          day of the first week (00..53)
  %W - Week  number  of the current year,
          starting with the first Monday as the first
          day of the first week (00..53)
  %w - Day of the week (Sunday is 0, 0..6)
  %x - Preferred representation for the date alone, no time
  %X - Preferred representation for the time alone, no date
  %y - Year without a century (00..99)
  %Y - Year with century
  %Z - Time zone name
  %% - Literal ``%'' character
   t = Time.now
   t.strftime("Printed on %m/%d/%Y")   #=> "Printed on 04/09/2003"
   t.strftime("at %I:%M%p")            #=> "at 08:56AM"
  
   datetime seconds, hours, days, weeks, months, and years
  
    Add below lines to one of your initializer files, e.g., config/environment.rb:
    DateTime::DATE.FORMATS[:short]="short %Y-%m-%d %H:%M:%S"
    Time::DATE.FORMATS[:short] = "short %Y-%m-%d %H:%M:%S"
    Date::DATE.FORMATS[:short] = "short %Y-%m-%d"
    modify view:
    <%= item.create_date.to_s(:short) %>
distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
today = DateTime.now
=> #<DateTime: 441799066630193/180000000,-301/1440,2299161>
birthday = Date.new(2008, 4, 10)
=> #<Date: 4909133/2,0,2299161>
days_to_go = birthday - today
time_until = birthday - today
=> Rational(22903369807, 180000000)
time_until.to_i             # get the number of days until my birthday
=> 127
hours,minutes,seconds,frac = Date.day_fraction.to_time(time_until)
[3053, 46, 57, Rational(1057, 180000000)]
- mm  = (now-la    st_cigarette).divmod(Rational(1, 1440))[0]
- past.days = mm / 1440
- past.hours = (mm % 1440) / 60
- past_minutes = mm % 60

timezone

def set_api_time_zone
  utc_offset = current.user.session && current.user.session.user ? current.user.session.user.time.zone.offset.to.i.minutes : 0
  user.timezone = ActiveSupport::TimeZone[utc.offset]
  Time.zone = user.timezone if user.timezone
  Time.zone.today
  Time.now.to.date
    # => Thu, 19 May 2011
  Time.now.in.time.zone('Melbourne').to_date
    # => Fri, 20 May 2011
end

Range step

range.step(2) {|x| puts x}


benchmark

require 'benchmark'
n = 1000000
def answer1 current.subdomain
  case current.subdomain
  when 'www', 'blog', 'foo', 'bar'
  else nil
  end
end
def answer2 current.subdomain
  nil unless  ["www", "blog", "foo", "bar"].include?(current.subdomain)
end
Benchmark.bmbm do |b|
  b.report('answer1'){n.times{answer1('bar')}}
  b.report('answer2'){n.times{answer2('bar')}}
end
Rehearsal -------------------------------------------
answer1   0.290000   0.000000   0.290000 (  0.286367)
answer2   1.170000   0.000000   1.170000 (  1.175492)
---------------------------------- total: 1.460000sec
              user     system      total        real
answer1   0.290000   0.000000   0.290000 (  0.282610)
answer2   1.180000   0.000000   1.180000 (  1.186130)
Benchmark.bmbm do |b|
  b.report('answer1'){n.times{answer1('hello')}}
  b.report('answer2'){n.times{answer2('hello')}}
end
Rehearsal -------------------------------------------
answer1   0.250000   0.000000   0.250000 (  0.252618)
answer2   1.100000   0.000000   1.100000 (  1.091571)
---------------------------------- total: 1.350000sec
              user     system      total        real
answer1   0.250000   0.000000   0.250000 (  0.251833)
answer2   1.090000   0.000000   1.090000 (  1.090418)


출처




by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

도심 속에서 만나는 자연. 골웨이 남쪽 바닷가 산책.

바다 건너 편-'골웨이 바닷가 산책'

골웨이 남쪽의 울페톤 다리(Wolfe tone Bridge)를 지나 클라다 길(Claddagh Quay)을 따라 걸으면,
멋진 바닷가 풍경이 나타납니다.
길이 꽤 길게 이어져서 해안선을 따라 걷다 보면 시간이 훌쩍 지나지요.
이곳을 골웨이를 떠나는 날 아침에 들렀습니다.
비가 계속 많이 내렸어요.
‘아. 비 맞기 싫어.’
‘아. 걷고 싶어.’
하기 싫은 걸 피하면 불쾌한 일이 줄지만,
하고 싶은 걸 한다면 그깟 불쾌감 따위야 뭐 대수겠어요.
모자를 뒤집어쓰고 해변을 거닐기 시작했습니다.
아침마다 뜀박질하는 사람들이 비를 쫄딱 맞으며 제 옆을 스쳐 가네요.

들풀-'골웨이 바닷가 산책'

강한 바람 탓에 바닥에 몸을 누인 들풀 너머로 조용히 출렁이는 바다가 보입니다.
조금 더 걸으니 빗살이 약해졌어요.

산책 나온 개-'골웨이 바닷가 산책'

동네 사람 하나가 개를 데리고 산책을 나왔습니다.
그들은 낯선 곳을 거니는 낯선 이를 보고 잠시 발걸음을 멈추었지만,
이내 아무것도 못 본 듯이 익숙한 길을 걸어갑니다.

바닷가-'골웨이 바닷가 산책'

빗살이 다시금 거세집니다.
모자 위를 때리는 물방울 소리가 썩 듣기 좋더군요.
잠시 멈추어 바다를 바라보았습니다.
자연은 거센 비에도 우왕좌왕하지 않습니다.
아.
저도 자연에 속하는데.
왜 그처럼 의연하지 못할까요?

방파제-'골웨이 바닷가 산책'

방파제 길을 따라 걸으니 갈매기 몇 마리가 머리 위를 스쳐 갑니다.
“끼룩~ 끼루룩~”
그들의 노랫소리에 답가라도 들려주고 싶지만, 가사가 끝까지 기억나는 노래가 없네요.
흘러간 옛 노래를 조금 흥얼거리자 갈매기들이 저 멀리 떠나갑니다.
마치 자동차 엔진 소리에 놀라 달아나는 새처럼 말이에요.
제 목소리도 그리 생소한가 봅니다.
아마 그 소리가 자연스럽지 못해 그렇겠지요.



by


Tags : , , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Git cheat sheet


ssh 키페어 만들기

ssh 키 페어 만들기

git 기본 명령어


git init  - 초기화
git add * - git에 파일 목록 넣기
git commit -am 'initial commit' - 커밋
git push repository_name master - 해당 브랜치에 커밋
git clone git@app.repo.com:app/app.git - 코드를 로컬로  복제
cd app
git pull - 변경사항 풀


git 환경 설정


git config --global --list
현재 설정정보 조회할 수 있습니다. --global옵션은 전역설정에 대한 옵션이며 현재 프로젝트에만 적용할때는 주지 않습니다.
git config --global user.name "사용자명"
사용자명을 등록합니다 (필수)
git config --global user.email "이메일주소"
이메일 주소를 등록합니다. (필수)
git config --global color.ui “auto”
터미널에 표시되는 메시지에 칼라를 표시해 줍니다.



gitignore 사용하기


.gitignore
git config --global core.excludesfile ~/.gitignore_global
git rm -r --cached .
git add .
git commit -m ".gitignore 완성!"
git stash branch branchname
git fetch
git merge
git pull (git fetch + git merge branchname)


로컬 변경 무시하고 저장소에서 받아오기

모든 로컬 변경을 스태쉬 한다.
git stash save --keep-index
저장한 stash를 지운다.
git stash drop

파일 하나만 저장소에서 불러오려면 이렇게 한다.
git checkout HEAD^ path/to/file/to/revert

그리고 저장소에서 풀 한다.
git pull


특정 커밋으로 돌아가기
http://stackoverflow.com/questions/4114095/revert-to-previous-git-commit
git reset --hard 0d1d7fc32

Send a pull request on GitHub for only latest commit
http://stackoverflow.com/questions/5256021/send-a-pull-request-on-github-for-only-latest-commit
git checkout -b upstream upstream/master
git cherry-pick <SHA hash of commit>
git push origin upstream



How can I rollback a github repository to a specific commit?
http://stackoverflow.com/questions/4372435/how-can-i-rollback-a-github-repository-to-a-specific-commit
git reset --hard <old-commit-id>
git push -f



참고 자료

http://git-scm.com/
http://github.com/
아웃사이더님의 git 명령어 정리
구글 검색



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!