/images/profile_no_background.png

김영천 블로그

S2 library를 이용하여 가까운 위치의 사용자 찾기

구글에서 제공하는 S2 라이브러리를 이용하여 현재 내 위치에서 가장 가까운 사용자 목록을 추출해보자. 서버 환경은 GAE, golang standard environment 이다. 이 글을 참고했다.

S2 라이브러리란?

S2 라이브러리는 구글에서 비공식적으로(not an official) 제공하는 구(球)형상 라이브러리이다(번역기 발췌). 기존의 대다수 라이브러리는 2차원 평면을 기준으로 좌표시스템을 구축하였지만 S2 라이브러리는 3차원 구를 기준으로 좌표계를 사용한다. 실제 지구는 평면보단 구(球)에 훨씬 가깝기 때문에 좀 더 정교하고 왜곡없는 지리 데이터베이스를 구축할 수 있다(이 역시 번역기 발췌).

Google App Engine Image API 삽질 후기

오늘은 GAE에서 제공하는 Image API를 사용하면서 겪은 어려움과 후기를 공유하고자 한다.

요구사항

  • GAE를 통해 업로드 된 이미지를 Google Cloud Storage(이하 GCS)에 보관, 파일 관련 정보를 datastore에 별도로 저장한다(업로드 한 사용자, 업로드 파일명, 업로드 날짜 등등). 이 이미지를 웹사이트를 통해 서비스를 하고싶다. 이 이미지는 사이즈가 모두 제각각인데 DSLR로 찍은 수십메가짜리 이미지부터 조그마한 썸네일 이미지까지 크기가 천차만별이다.
  • 동일한 이미지를 여러가지 사이즈로 출력해야 한다. 가령 DSLR로 찍은 이미지를 제공할 경우 우선 100px짜리 썸네일로 제공, 사용자가 썸네일을 클릭할 경우 이미지의 원본을 보여주고 싶다.
  • 사용자가 주로 모바일을 통해 서비스를 사용할것으로 예측되는데 사용자의 디바이스마다 최적화 된 크기의 이미지를 제공하고 싶다.

고민

위와 같은 요구사항을 충족시키기 위해 인터넷을 꽤 오래 뒤지고 다녔다. 처음에는 비트윈의 블로그 글을 보고 이걸 따라하면 되겠다 싶었다. 하지만 문제가 있었다. 이미지 업로드를 GAE에서 구현하다보니 이미지를 webp 형태로 변환하는 golang 라이브러리를 쓸 수가 없었다. 마찬가지로 온디멘드 리사이징도 GAE 위에서 돌리기엔 문제가 좀 있었다(내가 해결책을 못 찾은걸수도 있다). 결국 며칠동안 고민만 하고 코드를 한줄도 작성을 못해서 일단 무식한 방법으로라도 구현을 해보기로 했다. 그래서 아래와 같은 방법을 후보로 선정했다.

datastore에서 projection query 실행 시 time.Time이 int64로 반환되는 문제 해결하기

요구사항

datastore에 내 프로필을 방문한 사용자의 ID와 방문시간을 각각 string, time.Time 형식으로 저장하고 있다. 구조체로 보면 다음과 같다.

type Visitor struct {
	UserId string //조회한 프로필의 Id
	VisitorId string //방문자 Id
	VisitTime time.Time
}

이 데이터를 단순히 조회하면 한 사용자가 나를 여러번 방문할 경우 결과 리스트에 그 방문자가 여러번 출력된다. 나는 동일한 사용자가 여러번 반복해도 가장 최근에 방문한 기록만 보길 원했다. 즉 datastore에서 SQL 문법의 group by를 사용하고 싶었다. 내 요구사항을 SQL로 표현하자면 아래와 같다.

emacs 단축키 목록

emacs 단축키 목록

아래의 단축키들은 그누 이맥스 시작하기(한빛미디어) 책을 보면서 정리한 내용들입니다.

common

  • C-x s : 모든 버퍼 저장(y, n 또는 !)
  • C-x C-q : 버퍼 읽기/쓰기 전용상태로 swap
  • C-x C-x : 선택영역 끝간 이동
  • C-t : 글자 순서 바꾸기(toggle)
  • M-t : 단어 순서 바꾸기
  • C-x C-t : 문장 순서 바꾸기
  • M-c : 단어의 첫 글자만 대문자로 바꾸기
  • M-u : 한 단어를 대문자로 바꾼다.
  • M-l : 한 단어를 소문자로 바꾼다.
  • C-s C-w : 커서가 있는 곳의 단어를 탐색 문자열로 사용해 점진적 탐색을 시작한다.
  • C-r : 재귀 편집
  • C-M-c : 재귀 편집 종료
  • C-x { : 윈도우 가로폭 줄이기
  • C-x } : 윈도우 가로폭 늘리기
  • C-x ^ : 윈도우 세로폭 늘리기

버퍼목록(C-x C-b) 작업

  • d or k : 버퍼 삭제
  • DEL : 지정명령 취소
  • x : 명령 실행
  • ~ : 버퍼를 수정하지 않은 상태로 표시
  • % : 읽기전용/읽기쓰기 전환
  • 1 : 버퍼를 전체화면으로 띄운다.
  • 2 : 현재 버퍼와 다음 것을 수평으로 나눈 윈도우에 띄운다.
  • m : 윈도우에 띄울 버퍼 선택
  • v : 선택한 버퍼들 수평으로 띄우기
  • f : 버퍼 목록 윈도우를 선택한 버퍼로 바꾼다.
  • o : 다른 윈도우를 선택한 버퍼로 바꾼다.
  • q : 버퍼 목록 끝내기

북마크 작업

  • C-x r m : 현재 커서위치에 북마크 생성
  • C-x r b : 북마크로 이동
  • M-x bookmark-rename : 북마크 이름변경
  • M-x bookmark-delete : 북마크 삭제

북마크 목록(C-x r l) 작업

  • d : 삭제할 북마크 표시
  • r : 북마크 이름을 변경한다.
  • s : 나열된 북마크를 저장한다.
  • f : 현재 커서가 위치한 북마크를 화면에 띄운다.
  • m : 여러 개의 윈도우에 띄우기 위한 북마크를 표시한다.
  • v : 표시한 북마크를 화면에 띄우거나, 아무것도 표시된 것이 없으면 커서가 위치해 있는 북마크를 표시한다.
  • t : 북마크와 관련된 파일 경로의 표시를 바꾼다.
  • w : 북마크와 관련된 파일의 위치를 표시한다.
  • x: 삭제 표시된 북마크를 삭제한다.
  • u : 북마크 목록에서 표시한 것을 취소한다.
  • DEL : 북마크 목록의 이전 줄에 표시한 것을 취소한다.
  • q : 북마크 목록을 종료한다.
  • M-| : shell command on region
  • C-c C-o : 이전 명령으로 인한 출력을 자동으로 지운다.

Dired(C-x d) 명령

  • C : 파일 복사
  • d : 삭제할 파일 지정
  • D : 즉시 삭제여부를 묻는다.
  • e : 파일 편집
  • g : 디스크로부터 디렉토리를 다시 읽어온다.
  • G : 그룹 퍼미션 변경
  • k : 목록에서 해당 파일 삭제(디스크에는 남아있음)
  • o : 다른 윈도우에 파일을 열고, 그 윈도우로 이동한다.
  • C-o : 다른 윈도우에 파일을 열고, 그 윈도우로 이동하지 않는다.
  • P : 파일 출력
  • q : dired 종료
  • Q : 표시한 파일의 문자열을 질의-치환 한다.
  • x : 삭제 실행
  • m : 파일 선택
  • R : 파일명을 바꾼다.
  • u : 표시를 취소한다.
  • M-DEL : 모든 파일의 표시를 없앤다.
  • Z : 파일을 압축 또는 해제한다.
  • ! : 커서가 위치한 파일을 대상으로 shell 명령 실행
  • M-} : * 또는 D로 표시된 다음 파일로 이동
  • M-{ : * 또는 D로 표시된 이전 파일로 이동
  • %d : 정규표현식과 일치하는 파일에 삭제표시 한다.
  • %m : 파일을 선택하기 위한 정규식을 묻는다.
  • + : 디렉토리 생성
  • = : 현재 파일을 표시해둔 다른 파일과 비교한다.
  • > : 다음 디렉토리로 이동
  • < : 이전 디렉토리로 이동
  • s : Dired의 화면 표시를 날짜나 파일명 순으로 재정렬(toggle)

매크로 명령

  • C-x ( : 매크로 정의 시작
  • C-x ) : 매크로 정의 종료
  • C-x e : 매크로 실행

프로그래머를 위한 이맥스(C, C++ 모드 기준, 대부분 go-mode에서도 동작되는것으로 보인다)

  • C-M \ : 커서와 마크 사이의 각 줄을 들여쓴다.
  • M m : 현재 줄의 첫번째 비공백 문자로 이동한다.
  • M ^ : 현재 줄을 이전 줄에 붙인다.
  • M j : indent-new-comment-line
  • M a : 현재 명령문의 처음으로 이동한다.
  • M e : 현재 명령문의 끝으로 이동한다.
  • M q : 주석 내에 있다면 들여쓰기와 장식 등을 유지하면서 단락을 채운다.
  • C-M a : 현 지점을 둘러싸고 있는 함수 내부의 시작점으로 이동한다.
  • C-M e : 함수의 끝으로 이동한다.
  • C-M h : 커서를 함수의 시작점으로 이동하고, 끝에 마크한다.
  • C-c C-q : 들여쓰기 스타일에 따라 함수 전체를 들여쓴다.
  • C-c C-u : 현재 전처리 조건문의 시작 위치로 이동한다.
  • C-c C-p : 이전 전처리 조건문으로 이동한다.
  • C-c C-n : 다음 전처리 조건문으로 이동한다.