#TIL #elixirlang reply_success/2 파이프를 끝까지 태우려는 노력
’Functional Web Development with Elixir, OTP, and Phoenix (Lance Halvorsen, 2018)’ 책에서 간단한 함수 하나로 pipe operator를 끝까지 태우는 코드를 봤다. GenServer Behaviour 콜백 함수인 h...
’Functional Web Development with Elixir, OTP, and Phoenix (Lance Halvorsen, 2018)’ 책에서 간단한 함수 하나로 pipe operator를 끝까지 태우는 코드를 봤다. GenServer Behaviour 콜백 함수인 h...
간단한 예제 코드를 먼저 보자. alias __MODULE__ 명령문(statement)은 어떤 걸 하는 걸까?
git diff에서 변경된 줄을 나타내는 Hunk를 보여준다. @@ -418,6 +418,8 @@ 이런 식으로 라인 넘버를 같이 표시해 준다. 여기에 header를 출력해 변경 사항에 정보를 제공한다. 예를 들어 header에 포함된 함수나 클래스 선언을 보여줄 수 있다. 라인 넘...
GitHub에 있는 커밋을 내 저장소에 적용하고 싶다. 리모트 저장소로 등록을 안 한 상태라서 git cherry-pick 명령은 사용하지 못한다. 어떻게 하면 될까?
공개키를 접속하려는 서버 authorized_keys 파일에 추가하면 편하다. 패스워드 없이 접속할 수 있기 때문이다.
StreamData는 값을 생성하는 Elixir 라이브러리다. Property-based testing을 할 때, 주로 사용하고 있다.
build_list 라는 함수를 짜고 있다. 요소(element)를 원하는 개수만큼 생성하게 하고 싶다.
mix.exs 파일을 수정해 의존성을 추가해서 라이브러리를 사용하다가 mix.exs 파일에서만 의존성을 제거한다. mix.lock 파일에서도 지워야하는데, 그대로 놔뒀다. 이제 mix.lock 에 있어서 다운로드하지만 사용하지 않는 쓰레기 의존성이 생겼다.
서버를 실행하면 특정 포트(port)를 열다가 실패하는 경우가 있다. 이미 수신 대기하고 있는 포트라는 메시지가 보인다. windows에서는 netstat, findstr, taskkill 프로그램을 사용해서 특정 포트를 수신 대기하고 있는 프로세스의 ID를 찾아 해당 프로세스를 ...
elixir 대화형 셸(interactive shell)인 iex를 사용하면 코드를 evaluation해서 모듈을 실시간으로 추가할 수 있고 실행할 수 있다. iex 프로그램을 실행한다. 함수를 실행한다. 코드를 수정한다. 다시 컴파일한다. 함수를 실행한다. 이런 빠른 이터레이션이...
연말 정산을 하다가 암호가 걸린 PDF를 첨부해야 할 일이 생겼다. 암호를 풀고 첨부해야 하는데, macOS에서 제공하는 미리보기 프로그램으로 PDF를 열어서 암호화하지 않은 PDF로 익스포트 하는데 잘되지 않는다. 암호화가 풀린 게 아니라 내가 입력한 비밀번호를 기억해서 바로 열...
파인더에서 숨김 파일이 보이지 않아 불편해 변경했다.
winget을 사용하면 windows에서 커맨드라인으로 프로그램을 설치할 수 있다. apt-get, brew 처럼 손쉬운 설치가 windows에서 가능하다. 회사에서 코드 사이닝을 안 한 powershell 스크립트 파일을 사용 못 하게 도메인 정책으로 막아놓곤 해서 사용 못하던 ...
마이크로소프트에서 만든 윈도우 터미널(windows terminal)은 셸(shell)을 호스팅하는 애플리케이션(application)이다. 즉 이 애플리케이션을 사용해 cmd, bash, powershell 등을 띄울 수 있다. 화면 분할도 지원해서 그동안 사용하던 ConEmu를...
case val do 200 -> true 404 -> true _ -> false end
사내 linux 가상 머신 인스턴스에 gitlab runner를 설치하려고 했을 때였던 걸로 기억한다.
defaults write -g ApplePressAndHoldEnabled -bool false
’에어팟(AirPods, 2019) 2세대’를 잘 사용하고 있다. iOS, iPadOS 14 이후로 지원되는 자동 전환을 켜서 사용하고 있었다. macOS도 지원돼서 기기간 연결이 잘 넘어간다. macOS에서 음악을 듣다가 별도 작업 없이 iOS로 듀오링고를 켜서 영어 공부를 하면...
시스템 환경설정 > 사용자 및 그룹 > 로그인 항목
iex> match?(%{a: _}, %{a: 1, b: 2}) true iex> match?(%{c: _}, %{a: 1, b: 2}) false
닌텐도 스위치와 컴퓨터를 USB 케이블로 연결한다. 바로 인식하지 않는데, 별도 프로그램이 필요하다. 닌텐도 스위치 OS가 안드로이드인가보다. Android File Transfer 프로그램을 설치해야 한다.
map = for i <- 1..100, into: %{}, do: {i, Enum.random([false, true])}
defp ask_and_schedule(producers, from) do case producers do %{^from => {pending, interval}} -> # ... %{} -> # ... end end
EDATE(DATE(1969,7,20), 1) EDATE(B1,-3)
UTF-8 인코딩으로 출력하는 한글이 깨져서 한참 찾았다. locale 명령으로 인코딩 설정을 봐도 이상한 게 없다. 아~ windows에서 실행하는 거였지.
프로그래밍할 때는 숫자를 인자로 넣어서 pid(프로세스 아이디)를 만들 일이 없지만, elixir 대화형 셸(iex, elixir’s interactive shell)을 사용해 프로세스에 직접 메시지를 보낼 때, 가끔 사용한다.
때가 어느 때인데, EUC-KR 인코딩을 UTF-8 인코딩으로 변환하는 걸 찾아봐야 하는가? 대부분 UTF-8 인코딩을 사용하고 있지만 많은 레거시 시스템은 아직도 EUC-KR 인코딩을 사용하고 있다.
is_atom(nil)
csv로 저장하려고 했는데, jason 라이브러리를 사용하면 직렬화(serialization), 역직렬화(deserialization)가 편해서 json 포멧을 사용한다.
SomeModule.some_func(1, 2, 3) SomeModule.some_func(1, 3, 4, 5) SomeModule.some_func(1, 4, 5, 6, 7) SomeModule.some_func(1, 5, 6, 7, 8, 9) SomeModule.some_fun...
특정 디렉터리에 있는 파일 이름을 조회하고 싶어서 관련 함수를 찾아봤다. find_file 정도를 기대하고 찾아봤는데, 찾아봐도 없더라. 구글링해서 찾았다. Path.wildcard/2.
list를 인자로 받는 함수가 있을 때, list로 가공해서 넘겨야 한다.
{:ok, %{body: body}} = get("/list.xml") {:ok, result} = :zip.unzip(body, [:memory])
bash에서 고정 인자와 가변 인자가 섞여 있다면 어떻게 처리해야 할까?
프로젝트에 쓰는 패키지 중 버전이 올라간 패키지가 있을까?
이번에 배포한 브랜치를 언제 땄더라. a 커밋이 이번에 배포한 브랜치에 포함되었나?
프로메테우스(prometheus)와 그라파나(grafana)를 테스트하고 싶다. 간편하게 docker를 사용해서 띄우고 host에서 실행하는 웹프레임워크 메트릭을 보고 싶다.
Subversion provides the svn:executable property as a way to specify that the executable bit for the file on which that property is set should be enabled, ...
$ ls | sort --version-sort --reverse | grep -Po [0-9]+\\.[0-9]+\\.[0-9]+ | head -n 1
$ git pull ... Unlink of file 'xxxx' failed. Should I try again? (y/n)
$ find . -type f ! -name '*.txt' -delete
$ cat sample.csv 1,2,3,4,5 a,b,c,d,e A,B,C,D,E
$ git tag --list ‘v0.2*' --sort=-v:refname v0.2.25 v0.2.24 v0.2.23 v0.2.19 v0.2.18 v0.2.17 v0.2.16 v0.2.15 v0.2.14 v0.2.13 v0.2.12
```elixir def put_new(map, key, value) do case map do %{^key => _value} -> map
$ filename=20190131064326_abcdefghijk.exs $ echo `expr match "$filename" '\([0-9]*\)'` 20190131064326
iex> fruit = :orange :orange iex> fruit == :orange or fruit == :banana true
iex> Enum.find([1, 2, 3], fn x -> rem(x, 2) == 0 end) 2 iex> Enum.find_value([1, 2, 3], fn x -> rem(x, 2) == 0 end) true
timeout = opts[:timeout] || 10_000
iex> :timer.seconds(1) 1000 iex> :timer.minutes(1) 60000 iex> :timer.hours(1) 3600000 iex> :timer.hms(1, 0, 0) 3600000 iex> :timer.hms(1, 1, 1...
def join("videos:" <> video_id, _params, socket) do {:ok, assign(socket, :video_id, String.to_integer(video_id))} end
덤프가 안 남아서 왜 프로세스가 죽었는지 모를 때, 커널의 메시지 버퍼를 출력해서 보면 실마리를 찾을 수 있다.
문자열 부분 삭제로 원하는 정보를 간단하게 추출할 수 있다.
gitlab CI/CD 파이프라인 rules 설정 파라미터를 사용하면 특정 조건에만 파이프라인을 시작할 수 있다.
빌드 머신 저장 공간이 가득 찰 일은 없겠지? 저장 공간 FULL이 나서 빌드 몇 번 실패해보면 정신을 차린다. 너무 헤프게 쓰고 있었구나. 게다가 mac mini라 저장 공간을 바로 늘릴 수도 없다. 필요한 것만 checkout 해서 쓰자. checkout 속도가 빨라져 빌드하는...
$ find . -type f -print0 -name '*.sh' | xargs -0 dos2unix dos2unix: converting file ./hello world.sh to Unix format... dos2unix: converting file ./sub_test/h...
C:\> help for FOR /L %변수 IN (시작,단계,끝) DO 명령 [명령-매개 변수] 집합은 단계별로 증가/감소하는 시작부터 끝까지의 일련의 숫자입니다. 따라서 (1,1,5)는 1 2 3 4 5를 나타내며 (5,-1,1)은 5 4 3 2 1을 나...
cat << EOF > /tmp/yourfilehere These contents will be written to the file. This line is indented. EOF
$ command -v emacs /usr/local/bin/emacs $ echo $? 0 $ command -v vim $ echo $? 1
$ docker run \ > --name mysql-temp \ > -e MYSQL_ROOT_PASSWORD=supersecret \ > -d \ > --rm \ > -p 3310:3306 ...
:%s/foo/<c-r><c-w>/g Replace each occurrence of ’foo’ with the word under the cursor. means that you press Ctrl-R then Ctrl-W The word u...
$ git add sample.sh $ git update-index --chmod=+x sample.sh
$ echo -e '\n. $HOME/.asdf/asdf.sh' >> ~/.bashrc
iex> pool_config = %{name: "Auth"} iex> String.to_atom("#{pool_config[:name]}Supervisor") :AuthSupervisor
fileFormatVersion: 2 guid: de9a32f15f2628044842629a83d3d974 timeCreated: 1442592418 licenseType: Free MonoImporter: serializedVersion: 2 defaultReferences:...
$ docker run \ --name gerrit-mysql \ --volumes-from=gerrit-data \ -e MYSQL_ROOT_PASSWORD=123456 \ -e MYSQL_DATABASE=reviewdb \ -e MYSQL_USER=gerrit2 \ -e MYS...
defmodule Ticket do @enforce_keys [:origin, :destination, :price] defstruct @enforce_keys end
$ git archive --format=tar origin/master \ | gzip -9c \ | ssh USER@SERVER "mkdir -p TARGET_DIR; tar --directory=TARGET_DIR -xvzf -"
$ cat test.csv header1,header2,header3 1,2,3 2,3,1 3,1,2 $ sed -i.bak -e "1s/[^,]/x/g” test.csv $ cat test.csv xxxxxxx,xxxxxxx,xxxxxxx 1,2,3 2,3,1 3,1,2
배포에 SVN을 사용한다. 단순히 복사해서 커밋한다면 삭제한 파일 반영이 안 된다. 삭제된 파일을 반영해야 한다.
FortiClient를 설치했더니 로그인할 때마다 시작한다. 가끔 쓰는데, 계속 떠 있으니 내 노트북이 더러워지는 느낌이다.
iex> :ets.new(:test, [:named_table]) :test iex> :ets.insert(:test, {:key1, :value1}) true iex> :ets.insert(:test, {:key2, :value2}) true iex> :et...
iex> :dets.open_file(:storage, [{:type, :set}, {:file, "file"}]) ** (ArgumentError) argument error
$ ps -ax | grep beam
iex> answer = “yes" "yes" iex> "the answer is #{answer}" "the answer is yes"
$ mix run --no-halt > logs 2>&1 & [1] 2208 $ jobs [1]+ Stopped mix run --no-halt > logs 2>&1
$ sudo apt-get update
```elixir defmodule User do defstruct name: “ohyecloudy” end
대화형 터미널(interactive terminal)에서 쿼리 결과가 길면 pager가 편하다. 한 페이지에 결과가 다 안 보이기 때문이다. 앞뒤로 왔다 갔다 하면서 확인할 수 있어서 편하다. 하지만 결과가 짧거나 결과를 참고하며 이후 쿼리를 짜고 싶을 때는 pager가 방해된다.
리턴 값이 nil인지 검사해서 다른 값을 사용하는 것보단 nil일 때, 사용할 default 값을 인자로 넘길 수 있다면 로직이 깔끔해진다. 인자를 3개 받는 get_in/3을 기대했지만, get_in/2 밖에 없다. 필요하면 만들어 써야 한다.
$ docker run -e "TZ=Asia/Seoul”
gx 키를 누르면 url을 디폴트 웹브라우저로 연다.
$ git checkout master $ git merge -s ours obsolete-branch
iex> Enum.drop([1, 2, 3], -1) [1, 2] iex> Enum.take([1, 2, 3], -1) [3]
docker를 tpass 프로그램을 테스트하는 데 사용했다. 간단한 테스트다. 다음과 같은 순서로 진행한다. docker exec 명령을 내린다. 결과값을 검사한다. 다만 이렇게 하려면 컨테이너가 입력을 받을 수 있는 상태여야 한다. 즉, 실행 상태여야 한다. 종료하면 안 된다.
$ echo a/b/c/d | cut -d/ -f 2 b $ echo a/b/c/d | cut -d/ -f -2 a/b $ echo a/b/c/d | cut -d/ -f 2- b/c/d
$ for file in *.jpeg; do mv "$file" "$(basename "$file" .jpeg).jpg"; done
씬 로드 전에 함수를 호출할 방법이 있을까?
C:\> type open_project.cmd start "" "C:\Program Files\Unity\Editor\Unity.exe" -projectPath "C:\my_project"
${parameter:-word}
<#TIL vagrant로 centos, docker 세팅> 글처럼만 해도 편했는데, 더 편하게 할 수 있다.
Not enough random bytes available. Please do some other work to give the OS a chance to collect more entropy! (Need xxx more bytes)
$ git push origin :feature-1
Command(⌘)-Shift-4, 스페이스 바, 클릭
$ cd existing_repo $ git remote rename origin old-origin $ git remote add origin new_repo_url $ git push -u origin --all $ git push -u origin --tags $ git r...
C:\> ping 127.0.0.1 -n 6 > nul
require MyMacros alias MyMacros, as: My
#!/usr/bin/env bash
Cat cat = new Cat() cat.Age = 10; cat.Name = "Fluffy";
standard_init_linux.go:175: exec user process caused "no such file or directory"
cd "$(dirname "$0")/.."
>result.txt echo first line >>result.txt echo second line >>result.txt echo third line
| ge | Backward to the end of word | | gE | Backward to the end of WORD |
V 키를 눌러 visual mode 진입 후 영역을 선택한다. < 키를 눌러 왼쪽으로 옮긴다. 에이 2< 키 누를걸. 한 번 더 밀어야 하잖아. 이때 gv 키를 눌러 이전과 똑같은 영역을 선택한다. 그리고 다시 < 키를 누르면 된다.
vim은 변경이 일어난 곳을 기억한다. 끝이 안 보이는 문서에서 마지막 수정한 위치로 가려고 u 키로 undo를 해서 가던 무식한 날들은 이제 안녕.
$ MD="~/My Documents" $ echo "${MD}" ~/My Documents $ cd "${MD}" bash: cd: ~/My Documents: No such file or directory
$ cd My\ Documents $ pwd /c/Users/ohyecloudy/My Documents
g d 키는 로컬 정의(local definition)로 이동하고 g D 키는 글로벌 정의로 이동한다. 소스 코드에서 많이 사용한다. g d 키를 눌러서 정의를 보고 Ctrl o 키를 눌러서 원래 자리로 온다.
Command(⌘)-Shift-3
iex> c("lib/worker.ex")
MapSet.size(MapSet.difference(a, b)) == 0
Enum.fetch/2, Enum.fetch!/2 함수의 차이점은? 에러 발생 여부다
vim은 커서 위치를 jump list로 관리한다. `, /, n 등 커맨드로 이동할 때, 위치를 기록해 놓는다. 커서 위치를 바꾼다고 모두 저장하진 않는다. hjkl 키처럼 깨작깨작 움직이는 커맨드는 제외한다. jump list에 기록된 위치를 CTRL-I 키와 CTRL-O 키로...
unity ios 빌드는 xcode 워크스페이스 혹은 프로젝트를 만드는 것까지 책임진다. xcode로 바이너리를 뽑아내는 건 사용자가 해야 한다.
충돌(conflict)이 발생했을 때, 한쪽 변경 사항을 적용하고 싶다. 주로 테스트 데이터 커밋이다. 코드 변경 사항과 섞여 들어가지 않게 데이터만 따로 커밋을 만든다. push 전에 걸러내면 되니깐. 중앙 저장소에 있는 커밋을 로컬로 가져왔는데, 데이터에서 충돌이 발생했다. 이...
$ cat .git/HEAD ref: refs/heads/master
$ cat .gitignore *.c
def project do [ # ... aliases: aliases(), ] end
$ git fetch
제어 연산자(control operator)를 사용하면 한 줄에 여러 명령을 실행할 수 있다. 간단히 if 문(statement)을 쓴 효과를 누릴 수 있다.
defmodule MapUtil do def empty?(%{}), do: true def empty?(map), do: false end
iex> [key1: "value1", key2: "value2"] |> Enum.into(%{}) %{key1: "value1", key2: "value2"}
$ git checkout --track origin/serverfix
1 { 2 { 3 { |4 } A } B }
svn: warning: cannot set LC_CTYPE locale svn: warning: environment variable LANG is KOR svn: warning: please check that your locale name is correct
C:\> PowerShell -Command "(Get-Content input.txt) | Set-Content -Encoding utf8 output.txt"
$ pacman -Sy
cmd가 최신. 호환성을 끊고 새로운 기능을 추가하려고 bat가 아닌 새로운 확장자를 추가한 것 같다. %ERRORLEVEL% 변수 세팅 정책이 다른 건 주의해야 한다.
pre { + white-space: pre; - white-space: pre-wrap; - word-wrap: break-word; + word-wrap: normal; + overflow-x: auto; }
$ git config --global alias.stsh 'stash --keep-index' $ git config --global alias.staash 'stash --include-untracked'
$ git fetch --prune $ git pull --prune
[alias] pu = "!f() { \ [[ $(git config \"branch.$(git symbolic-ref --short HEAD).merge\") = '' ]] && \ gi...
ohyecloudy@air5 ~/project/ddiary (master) $
지오태깅 프로그램을 찾다가 ExifTool을 알게 됐다. 기능 많네. 지오태깅 뿐만 아니라 rename, move도 지원한다.
지오태깅이 안 되는 옛날 카메라를 사용하고 있다. GPS 로그는 Moves 앱을 사용해서 기록하고 Moves Export를 사용해서 GPX 포맷으로 저장한다.
$ find / -name 'to_be_searched.file'
MSYS2 refers to the libraries and programs that use the POSIX emulation layer (“msys2 runtime”, derived from Cygwin’s cygwin1.dll). It i...
${BUILD_LOG_MULTILINE_REGEX, regex=".*error [A-Z]+[0-9]+:.*"}
$ git log -SText
set TEST_VAR=C:\test\data\test.txt set TEST_VAR=%TEST_VAR:\=/% echo %TEST_VAR%
echo ENV_1=%ENV_1%>propsfile echo ENV_2=%ENV_2%>>propsfile
C:\>FOR %A in ("C:\Users\ohyecloudy\test folder\test.txt") DO @ECHO %~dpA C:\Users\ohyecloudy\test folder\
C:\>ECHO abcd > test.txt
set /p VERSION=<version.txt
* 키로 찾던가 아님 / 커맨드로 찾던가하면 일치하는 단어가 강조된다. 다음 찾기를 할 때까지 강조가 유지된다. 지우고 싶을 때면 /adfafddsaf 처럼 일치하는 단어가 없게 마구잡이로 넣어서 강조를 지웠다.
]] sections forward or to the next ‘{’ in the first column.
$ du -h ~/.emacs.d/init.el 8.0K /Users/ohyecloudy/.emacs.d/init.el
Since Apple decided not to load 3rd party plugins, we have to make change to it. What we have to do overall is to re-codesign Xcode. This allows us to loa...
$ curl -s http://support-sp.apple.com/sp/product?cc=`system_profiler SPHardwareDataType | awk '/Serial/ {print $4}' | cut -c 9-` | sed 's|.*<...
$ git add -p <pathspec>
Start an interactive rebase with git rebase -i <commit>^, where <commit> is the commit you want to split. In fact, any commit range will ...
#!/bin/sh ... export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH" exec node_modules/.bin/hubot --name “hubot" "$@...
:v/warning/d
* item1 * item2
batch script
$ npm install hubot-test-helper --save-dev
C:\> svn info %SVN_URL%/branches/%BRANCH_NAME% C:\> git ls-remote --exit-code --heads %GIT_URL% %BRANCH_NAME%
$ gem update jemoji Updating installed gems Updating jemoji Fetching: jemoji-0.6.2.gem (100%) ERROR: While executing gem ... (Gem::FilePermissionError) ...
$ docker exec -i gerrit ls /var/gerrit/review_site/plugins delete-project.jar events-log.jar $ docker cp reviewassistant.jar gerrit:/var/gerrit/review_site/...
$ git clone --recursive https://gerrit.googlesource.com/gerrit $ cd gerrit/plugins $ git clone https://gerrit.googlesource.com/plugins/reviewassistant/ $ cd...
Vagrant.configure(2) do |config| $script = <<-SHELL ... source ~/.profile if [ -z "$JAVA_HOME" ]; then export JAVA_HOME=...
$ sudo tee /etc/yum.repos.d/docker.repo <<-'EOF' [dockerrepo] name=Docker Repository baseurl=https://yum.dockerproject.org/repo/main/centos/$r...
$ cat Vagrantfile # -*- mode: ruby -*- # vi: set ft=ruby :
$ docker run --rm --volumes-from $DATA_VOLUME_CONTAINER_NAME -it ubuntu bash
grep -r --include='*.txt' --include='*.xml' texthere .
$ cat $GERRIT_SITE/etc/gerrit.config | grep -A 1 auth [auth] type = DEVELOPMENT_BECOME_ANY_ACCOUNT
출력 자체를 막을 순 없고 null 디바이스에 리다이렉션(redirection)해서 출력을 감춘다.
레지스트리에서 이미지를 다운로드 받고 격리해서 실행하는데 필요한 설정을 추가해서 컨테이너를 생성해 실행한다. 데이터 볼륨을 만들어서 컨테이너에 마운트해서 사용할 수 있다.
C:\> netsh advfirewall firewall add rule name="inbound" dir=in action=allow protocol=tcp localport=3399 C:\> netsh advfirewall firewall add ...
바퀴 자국 안에 빠지게 되면 아무리 바퀴를 돌려도 계속 제자리고, 유일한 진척이라고는 더 깊게 파이는 자국뿐이다. from 트와일라 타프, 'The Creative Habit' {프로그래머의 길, 멘토에게 묻다}— 프로그래밍 책 인용 봇 (@book_quo...
랜덤으로 뽑아 트윗할 인용구들을 어디에 저장할까? 가장 인기 있는 인용구나 이런 정보를 수집하고 싶다. 이러면 DB를 사용하는 게 가장 편하다. 하지만 그건 좀 먼 일. 이건 나중에 고민하기로 한다.
root path에 config.clj를 뒀다. 실수로 체크인하지 않게 gitignore에 추가. 귀찮은 parsing을 할 필요 있겠어? clojure map을 사용했다. 이 파일을 평가하면 map이 만들어진다. 편하네.
Hello, Twitter!— 프로그래밍 책 인용 봇 (@book_quote_bot) May 8, 2013
가독성 테스트를 할 좋은 글을 찾았다. 법륜스님 주례사 새겨들을 훌륭한 말씀.