전체보기


얼마 전 친구에게 이른 생일선물로

라미 사파리 만년필을 선물받았다.


블로그를 시작한 지 얼마 되지 않은 터라

받자마자 신나서 다 뜯어서 써보기까지 하고

집에 와서 뒤늦게 다시 포장하여 개봉기를 남긴다.


선물 받은 제품은 바로

라미 사파리 만년필 차콜블랙


< 쇼핑백과 깔끔한 패키징 >


위와 같이 심플한 박스 안에 포장되어 있다.

원래는 포장지까지 있었는데 다 찢어버리는 바람에 
개봉기를 쓸 때는 원래 없었던 것처럼..


박스를 열면 영롱한 만년필이 자태를 드러낸다.

전면에 보이던 LAMY 로고가 덮개를 고정하는 역할을 해준다.

구성은 만년필 본체와 잉크 카트리지 2개(흑색/남색)로 되어있다.


< 구성품 >


만년필 본체를 살펴보면 
뚜껑 부분에 이름이 각인되어 있고 
중앙부에 황토색 링이 보인다.

이는 초기에 들어있는 카트리지와의 
결합을 막기 위한 것으로 
실제 사용시에 제거해주어야 한다.


< 카트리지 결합 방법 >


만년필 뒤쪽 부분을 돌려서 연 뒤,
중앙부 링을 제거하고 카트리지를 꾹 눌러주면
딸깍 소리와 함께 만년필과 결합된다.

처음엔 샐까봐 무서워서 손가락으로 눌렀었는데 
이게 생각보다 세게 눌러주어야 해서 
바닥에 대고 꽉 눌러주는걸 추천한다.


< 카트리지 결합 후 모습 >


잉크 카트리지를 결합하고 나면 위와 같은 모습이 된다.

흑색을 써볼까 하다가 남색으로 선택!




아래는 만년필로 써본 글씨들인데...
만년필 사용이 처음이라 타 만년필과 비교는 불가능하기 때문에

주관적인 느낌만 얘기해보자면,

일단 다른 볼펜에 비해 필기감이 굉장히 부드럽다!

굵기는 생각보다 두꺼워서 0.4-5mm 정도 되는 펜과 비슷한 것 같다.

만년필 하면 필기시에 잉크가 굉장히 많이 나올 것 같았는데

노트에 적을때는 생각보다 번짐에 대한 걱정 없이 써도 괜찮았다.

악필이라 내 글씨 사진까지 올리고 싶지 않았지만, 
첫 리뷰이니 창피함을 무릅쓰고 올려본다.


< 라미 사파리 만년필로 적은 글씨들 >


결과적으로 굉장히 만족스러운 선물이다.

무광 블랙 바디에 영문으로 이름까지 각인되어 있어서
나름 고급스러운 느낌...?
필기감도 좋아서 가방에 매일 가지고다니던
펜 대신 들고다닐 예정이다.

잉크도 여분이 하나 남았으니 
부지런히 써서 다른 색 잉크도 사용해봐야겠다.




  요약


JDK에 포함된 jarsigner를 이용해 jar파일 또는 안드로이드 apk파일에 서명하는 경우 발생하는 타임 스탬프관련 경고 메시지를 없애는 방법



  증상 및 원인


jarsigner를 이용해 리패키징한 안드로이드 apk파일에 서명하던 도중 아래와 같은 경고 메시지를 발견했다. 서명은 정상적으로 되었기 때문에 무시해도 상관없으나 왠지 찜찜하여 원인과 해결 방법을 알아보았다.


Warning:

No -tsa or -tsacert is provided and this jar is not timestamped. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date <yyyy-mm-dd> or after future revocation date.


< 발생한 경고 메시지 >




서명 인증서가 만료되면 배포 된 파일을 다시 서명해야 하기 때문에 이런한 문제를 해결하기 위해 재서명이 필요없는 URL 기반 인증 방식인 타임 스탬프를 이용한 서명을 권장하는 것으로 확인된다. 관련 Oracle 문서에는 J2SE 5.0부터 추가 된 기능이라고 나와있으나 기존에 사용하던 JDK 버전(1.7021)에서는 경고 없이 서명이 되었던걸로 보아 이후 버전에서 발생하는 것으로 보인다.



  해결 방법


서명 시, -tsa 옵션과 함께 인증 기관 URL을 입력해주면 경고 메시지 없이 서명이 가능하다.


-tsa http://timestamp.digicert.com


< Timestamp를 이용한 서명 결과 >



  관련 포스팅




 

 

  요약

 

다수의 스레드를 사용한 C/C++ 프로그램에서 clock() 함수를 이용했을 때 발생하는 문제점과 clock_gettime() 함수를 이용하여 수행 시간을 정확하게 측정할 수 있는 방법을 설명한다.

 

 

  clock() 함수를 이용한 시간 측정 방법과 그 문제점

 

일반적으로 C/C++ 프로그래밍 시, <time.h>에 포함된 clock() 함수를 이용하여 아래와 같은 방식으로 수행 시간을 측정한다.

 

clock_t begin, end;

 

begin = clock(); 

 

/ *

 

수행 시간 측정을 원하는 작업

 

* /

 

end = clock();

 

cout << ((end - begin) / CLOCKS_PER_SEC) << endl;

 

이 방법은 싱글스레드 프로그램에서는 정상적으로 동작하나 멀티스레드 프로그램에서 사용할 경우, 시간 측정이 올바르게 되지 않는 것을 확인할 수 있다. 이는 clock() 함수가 단순히 프로세스에 의해 사용 된 클럭 수를 리턴해주기 때문에 하나의 스레드에서 위의 코드를 이용해 시간을 측정하는 동안 다른 스레드의 동작에 의해 클럭 값이 증가하게 되기 때문이다.


 


 

  clock_gettime() 함수를 이용한 올바른 시간 측정 방법

 

정확한 수행 시간을 측정하기 위해서는 <time.h>에 포함된 clock_gettime() 함수를 이용해야 한다. clock_gettime() 함수는 시간을 측정할 시계의 타입을 정의하는 clockid_ttimespec이라는 구조체를 인자로 갖는다.

  • clockid_t : 시계의 타입을 나타내는 인자로써, POSIX에서는 기본적으로 2가지 타입을 제공한다.

  • CLOCK_REALTIME

    시스템 전역에서 사용되는 실제 시간 (Epoch 기준)

    CLOCK_MONOTONIC

    특정 시점 이후로 흐른 시간 (ex. 부팅 후 시간)

  • timespec : 초와 나노초를 멤버로 갖는 구조체. <time.h>에 정의되어 있음.
struct timespec {
        time_t   tv_sec;        /* seconds */
        long     tv_nsec;       /* nanoseconds */
};

 

clock_gettime() 함수는 clockid_t에 입력한 시계를 이용하여 시간을 측정하므로 프로세스에서 사용한 클럭 수를 세는 clock() 함수보다 정확한 수행 시간 측정이 가능하다. 사용 방법은 다음과 같다. clockid_t의 인자로 CLOCK_MONOTONIC 대신 CLOCK_REALTIME을 사용해도 되지만 CLOCK_REALTIME 사용 시, 시간 측정 중에 시스템 시간이 변경될 경우 측정값이 변한다는 문제점이 있다.

 

struct timespec begin, end ;

 

clock_gettime(CLOCK_MONOTONIC, &begin);

 

/ *

 

수행 시간 측정을 원하는 작업

 

* /

 

clock_gettime(CLOCK_MONOTONIC, &end);

 

cout << (end.tv_sec - begin.tv_sec) + (end.tv_nsec - begin.tv_nsec) / 1000000000.0 << endl;

 

 

 

 

 

  요약

 

리눅스에서 홈 디렉토리 아래에 위치하는 8개의 사용자 폴더(Desktop, Documents, Downloads, Music, Pictures, Public, Templates, Videos)의 기본 경로를 변경하는 방법에 대해 설명한다.

 

 

  변경 방법

 

디렉토리의 경로는 user-dirs.dirs 라는 파일에 저장되어 있다. nano, gedit 등의 에디터를 통해 아래의 파일을 열어준다.

 

~/.config/user-dirs.dirs

 

파일을 열어보면 기본 설정은 아래와 같다. 여기서 빨간색으로 밑줄 친 부분을 원하는 경로로 바꿔준 뒤 재부팅 또는 재로그인을 해주면 경로가 변경된 것을 확인할 수 있다.

 

XDG_DESKTOP_DIR="$HOME/Desktop"
XDG_DOWNLOAD_DIR="$HOME/Downloads"
XDG_TEMPLATES_DIR="$HOME/Templates"
XDG_PUBLICSHARE_DIR="$HOME/Public"
XDG_DOCUMENTS_DIR="$HOME/Documents"
XDG_MUSIC_DIR="$HOME/Music"
XDG_PICTURES_DIR="$HOME/Pictures" 
XDG_VIDEOS_DIR="$HOME/Videos"


 


 

  예시

 

user-dirs.dirs 파일을 열어 문서 디렉토리를 '~/Desktop/문서'로 변경한 결과이다.

 

 

기본 문서 폴더의 경로가 '~/Documents'에서 '~/Desktop/문서'로 변경된 것을 확인할 수 있다.

 

 

 




오랜만에 하는 안드로이드 개발이라 스와이프 가능한 탭 메뉴를 만들기 위해 안드로이드 개발자 페이지를 찾아볼 수 밖에 없었다. 그런데 프로젝트를 만드는 도중 이를 안드로이드 스튜디오에서 샘플 코드로 제공한다는 것을 뒤늦게 알아버렸다...

 

 

  예제 코드를 이용해 스와이프 가능한 액션바 탭 만들기 (ViewPager와 Fragment 이용)

 

먼저 새 프로젝트 생성 창을 띄우고 앱 이름과, 도메인 등을 결정하고 액티비티 생성 페이지로 넘어간다.

 


Tabbed Activity를 선택하고 Navigation StyleAction Bar Tabs (with ViewPager)로 설정한다.




위와 같이 설정하면 액션바 아래에 3개의 탭을 갖는 초기 화면이 만들어진다. 이제 여기서 만들고자하는 앱에 맞게 불필요한 부분들을 제거하거나 수정해주면 된다. 나의 경우 타이틀 바와 탭 하나 등을 제거하였다.






  타이틀 바 제거하기


activity_main.xml 에서 Toolbar 코드를 제거한다. 마찬가지로, MainActivity.java 에서도 Toolbar 관련 코드를 제거해준다. 그리고 불필요해진 onCreateOptionsMenu 함수와 onOptionsItemSelected 함수도 제거해준다.





  실제 이용할 Fragment로 기존 Fragment 대체하기


예제 코드에서는 탭이 변경될 때마다 구성이 같은 프래그먼트를 보여준다. 나는 두 개의 화면이 필요해서 PlaceholderFragment 클래스를 삭제하고 새로운 프래그먼트 2개와 그 레이아웃을 만들었다. 그리고 SectionPagerAdapter getItem 함수를 새로 만든 프래그먼트의 인스턴스를 반환하도록 수정한다.




  결과 화면


타이틀 바를 제거하고 탭을 2개로 줄인 결과 화면. 이제 각각의 탭에 들어가는 프래그먼트에 기능만 구현해주면 된다.






  설명


리눅스에서는 'grep' 명령어를 통해 원하는 문자열 패턴을 포함하는 행들을 출력할 수 있다.

입력 파일이 있을 경우 입력 파일 내에서, 없는 경우 표준 입력 내에서 지정한 패턴을 검색하여 일치하는 행을 출력한다.



  사용법


기본적인 사용법은 아래와 같다.


grep [OPTIONS] PATTERN [FILE]


'grep' 명령어는 단독으로 사용되기도 하지만 'find' 같은 출력 명령어와 함께 사용하여 원하는 결과를 필터링하는 데에도 자주 사용된다.


출력명령어 | grep PATTERN


'grep' 명령어에서 사용할 수 있는 옵션은 다음과 같다.


 옵션

설명 

 -c

 패턴을 포함하는 행을 출력하는 대신, 일치하는 행의 수를 출력

 -L

 패턴을 포함하지 않는 파일의 이름을 출력

 -l

 패턴을 포함하는 파일의 이름을 출력

 -m [NUM]

 파일당 일치하는 행을 최대 NUM 개까지만 출력

 -o

 일치하는 부분만 출력

 -q

 결과를 출력하지 않음

 -s

 잘못된 입력 파일에 대한 오류 표시하지 않음

 -i

 대소문자 구분하지 않음 

 -v

 패턴과 일치하지 않는 행만 출력

 -n

 행 번호를 함께 출력

 -w

 패턴과 같은 단어를 정확하게 포함하는 행만 출력

 -x

 패턴이 전체 행과 일치하는 행만 출력

-r

 서브 디렉토리의 파일까지 모두 검사

 -a

 바이너리 파일을 텍스트 파일처럼 인식하여 검사





  사용 예제


1. 현재 디렉토리에서 'server' 를 포함하는 파일을 찾아서 출력



2. 현재 디렉토리의 파일 중 'lecture' 라는 문자열을 포함하는 파일만 출력



3. 현재 디렉토리의 모든 파일을 대상으로 'char' 라는 문자열을 포함하고 있는 행 출력



4. 3의 결과에 -w 옵션을 추가하여 정확하게 'char' 라는 단어를 포함하는 행만 출력







리눅스에서는 'df' 'du' 명령어를 이용해 디스크 용량을 확인할 수 있다.


df [OPTIONS] [FILE] : 시스템에 마운트 된 디스크의 남은 용량을 확인하는 명령어. 아래와 같은 옵션과 함께 사용 가능하다.


 옵션

 설명

 -a

 모든 파일 시스템을 출력

 -B [SIZE]

 지정 크기를 블록 단위로 하여 용량 표시

 -h

 용량을 가장 보기 편한 단위로 변환하여 보여줌 (ex. 1K, 256M, 4G)

 -H

 용량을 1024가 아닌 1000단위로 표시

 -i

 inode의 남은 공간, 사용 공간, 사용 퍼센트를 출력

 -k

 '-B 1K'와 같은 의미

 -l

 출력 목록을 로컬 파일 시스템으로 제한

 -P

 POSIX에서 사용되는 형태로 출력

 -t [TYPE]

 출력 목록을 파일 시스템의 타입(TYPE)으로 제한

 -T

 파일 시스템의 타입을 같이 출력 (ex. ext4)

 -x [TYPE]

 출력 목록에서 파일 시스템의 타입(TYPE)만 제외




du [OPTIONS] [FILE] : 파일의 디스크 사용량을 확인하는 명령어. 아래와 같은 옵션과 함께 사용 가능하다.


 옵션

 설명

 -a

 현재 디렉토리 아래의 모든 파일과 디렉토리의 사용 정보를 출력

 -B [SIZE]

 지정 크기를 블록 단위로 하여 용량 표시

 -b

 바이트 단위 출력

 -c

 출력된 의 사용량 합계 표시

 -D [FILE]

 입력한 심볼릭 링크 파일만 역참조(원본 파일의 용량을 출력)

 -h

 용량을 가장 보기 편한 단위로 변환하여 보여줌

 -H

 '-D' 옵션과 동일한 기능 수행

 -k

 '-B 1K' 옵션과 동일한 기능 수행

 -l

 하드 링크 파일일 경우, 여러번 용량을 카운트(원본과 하드 링크 파일 모두 카운트)

 -L

 모든 심볼릭 링크 파일들을 역참조

 -S

 서브디렉토리들은 결과에서 제외

 -s

 전체 사용량만을 출력

 -x

 다른 파일 시스템의 디렉토리는 결과에 포함하지 않음





 

안드로이드에서 무음/진동/벨소리 모드를 받아오거나 설정하는 방법은 아래와 같다.

 

AudioManager audioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);

if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL) {

// 벨소리 모드일 경우
}
else if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {

// 진동 모드일 경우

}
else if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {

// 무음 모드일 경우

}

AudioManager audioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL); // 벨소리 모드로 변경
audioManager.setRingerMode(AudioManager.RINGER_MODE_VIBRATE); // 진동 모드로 변경
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT); // 무음 모드로 변경

 

위의 코드는 벨소리, 진동 모드에서는 잘 동작하나 무음모드 설정/해제시에 에러가 발생

 

아래와 같이 방해금지 설정 변경 권한을 주어 해결 가능하다.

 

NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (!notificationManager.isNotificationPolicyAccessGranted()) {

context.startActivity(new Intent(android.provider.Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS));
}

 

 

 


 

 

기존의 apk파일을 별도의 프로그램 없이 리패키징하는 방법입니다.

 

 


 

먼저 apk파일의 확장자를 zip으로 변경 후 압축을 풀어줍니다.


파일의 확장자가 보이지 않는 경우, 


도구 - 폴더 옵션의 보기 탭에서 '알려진 파일 형식의 파일 확장명 숨기기' 항목을 선택 해제합니다.

 

 

 

 

 

압축을 풀고 나면 다음의 구성요소들을 확인할 수 있습니다.

 




 assets

 패키지 내에 포함된 비 리소스 파일 

 META-INF

 apk 배포시 서명한 내용. 

파일 변조 시 패키지 손상 오류가 뜨며 기기에 설치가 되지 않음

 res

 리소스 파일

 AndroidManifest.xml

 Manifest

 classes.dex

 달빅에서 동작하는 컴파일 된 실행 파일

 resouces.arsc

 컴파일 된 리소스 파일



assets과 res 폴더에는 파일이 그대로 들어있기 때문에 수정 및 변경이 가능합니다.


소스코드의 경우 별도의 디컴파일 툴들(Dex2jar, JD-GUI, Apk manager, Apktool 등)을

 

사용해야만 확인할 수 있습니다.

 

 

수정이 끝나면 기존 서명은 효력을 잃게 되기 때문에 


패키지 폴더 내의 'META-INF' 폴더를 삭제한 후 다시 zip파일로 압축해줍니다. 


이 때, 고급설정 - 압축방법 - 압축 안함 옵션을 선택해 압축합니다. (알집의 경우)

 

 

 

 

마지막으로, zip파일 확장자를 다시 apk로 변경 후 재서명하면 리패키징이 완료됩니다.


서명을 위해 JDK 내에 포함된 'jarsigner'를 사용합니다.


cmd창에서 다음의 명령어 입력 후 패스워드를 입력하면 서명이 완료됩니다.

 

> jarsigner -verbose -keystore [your keystore file] [your apk file.apk] [your keystore alias]

 


JDK가 설치되어 있지 않을 경우, 아래의 링크에서 사용하는 OS에 맞게 다운받아 설치합니다.


Download JDK



JDK 설치 이후에도 아래와 같은 문제 발생 시,


'고급 시스템 설정' 창에서 '환경 변수'를 클릭하여 시스템 변수 목록에서 Path를 찾습니다.

가장 끝에 ';[JDK 설치 경로]\bin'을 추가한 뒤 cmd를 재실행하면 해결됩니다.




 


 

리눅스에서 gcc, g++ 컴파일러를 이용하여 코드를 컴파일 시 다양한 최적화 옵션 사용이 가능하다.

 

 

$ g++ -(optimization options) test.cpp

 

 

각 옵션들은 매우 다양하기 때문에 일반적으로 이들을 묶어 간편하게 사용 가능한 '-O1', '-O2', '-O3' 옵션을 사용한다.

 

KLDP에서 설명하는 각 옵션의 최적화 방식은 다음과 같다.

 

 

'-O1'의 경우, 만들어지는 오브젝트, 또는 실행 파일을 가능한 작게 하면서, 컴파일 시간이 오래걸리지 않는 선에서 최적화를 수행.

'-O2'의 경우, 만들어지는 코드가 가능한 빠르게 수행되도록 하지만, 코드의 크기가 너무 커지지 않도록 하는 선에서 최적화를 수행.

'-O3'의 경우, 코드의 크기는 전혀 신경 쓰지 않고, 오직 빠른 코드를 만들어 내기 위해 최적화를 수행.

 


 

KLDP에서는 '-O2' 옵션과 '-O3' 옵션의 속도에 대해 아래와 같이 설명하는데, 직접 다양한 코드에 사용해 본 결과 속도는 '-O2'와 '-O3' 옵션이 비슷한 성능을 보인다.

 

 

'-O3'로 만들어낸 코드가 반드시 '-O2'를 써서 만들어낸 코드보다 빠르다는 보장은 없다는 것입니다.

왜냐하면, 보통 CPU가 기계어를 수행할 때, 일정한 분량만큼 먼저 CPU 내부의 cache(캐시)에 불러와서 수행하는데, '-O3'를 써서 만든 코드는 대개 크기가 커서, 이 cache에 들어갈 수 있는 명령의 양이 상대적으로 적어지기 때문에, 오히려 느려질 가능성도 있습니다.

 

 

하지만 최적화 옵션을 사용하고 안하고는 차이가 크니 컴파일시 꼭 사용하는 것을 추천한다.

 

 

 

+ Recent posts