JS

2013년 9월 28일 토요일

기기 관리자 문제 해결

문제가 발생하는 원인:
* OTA를 빨리 받기 위한 방법 중에 Google Services Framework의 데이터를 지우는 방법이 있다. 그런데 이 방법을 적용하면 몇 가지 문제가 발생하기도 한다.

안드로이드 기기 관리자에 내 기기가 안 보이는 경우

참고: https://support.google.com/accounts/answer/3265955?hl=ko

1. Google 설정에서 원격 기기 초기화 허용을 비활성화한다.
2. 설정 > 애플리케이션에서 Google Play 서비스의 데이터를 지운다.
3. Google 설정에서 원격 기기 초기화 허용을 활성화한다.
4. 기기를 리부팅하고 기다린다.

구글 플레이 스토어에서 내 기기가 안 보이는 경우 (앱 원격 설치 불가능)

참고: https://support.google.com/googleplay/answer/1141080?hl=en

1. 설정 > 애플리케이션에서 Google Play 스토어의 데이터를 지운다.
2. 플레이 스토어를 다시 실행하면 약관 동의를 묻는 창이 다시 나올 것이다. 여기에 동의하고 기다린다.

2013년 9월 27일 금요일

넥서스 7 (2013) OTA 실패

넥서스 7 (2013)을 루팅 등을 하지 않고 순정 상태로 사용 중이었다. 그런데 시스템 업데이트 과정에서 오류가 발생하였다. 처음에는 일시적인 오류라고 착각을 했는데, 같은 오류가 두세번 반복되고 난 후, 내 넥서스 7에 문제가 있다는 것을 알게 되었다. 오류가 발생한 화면에서 volume up key + power key를 누르면 recovery mode가 나오면서 어디서 오류가 발생했는지도 볼 수 있다. 에러 메시지는 다음과 같았다.

Finding update package...
Opening update package...
Verifying update package...
Installing update...
Verifying current system...
assert failed: apply_patch_check("/system/framework/framework-res.apk", "d6ff2a1767bec4e906ee8498fc852d74c16e328d", "b92dd7bde4e18298ee24053ba36436f4f03fcb79")
E:Error in /cache/58a0583c950458ab96dc1fc29b020c6782493c3b.signed-razor-JSS15R-from-JSS15Q.58a0583c.zip
(Status 7)
Installation aborted.

정상적인 방법으로 OTA를 시도한 경우에도 실패했고, adb sideload를 이용한 방법도 실패했다. 공장 초기화를 한 후 다시 시스템 업데이트를 시도한 경우에도 실패했다. 모든 경우에 위와 같은 assert failed 메시지가 나타났다.

* 루팅을 시도하지도 않았고, 커스톰 롬을 설치하지도 않았다.

* 설정의 메뉴에서 공장 초기화를 해도 문제는 해결되지 않았다.

* 리커버리 모드에서 공장 초기화를 해도 문제는 해결되지 않았다.

* 위 메시지에서 assert failed에 해당하는 부분은 OTA update 파일에서 META-INF/com/google/android/update-script의 line #196에 해당하는 내용이다.

* 루팅은 하지 않았고, 시스템 파티션에 read-only로 접근 가능하다. adb pull /system/framework/framework-res.apk로 JSS15Q 상태의 기기에서 framework-res.apk를 추출한 후 sha1sum을 해보니 결과는 b92dd7bd... 이였다.

* Factory image의 압축을 해제한 후 apk의 파일을 추출할 수 있다 (참고1, 참고2). 요약하면 sgs2toext4.jar을 이용하여 .img 파일을 .ext4.img 파일로 바꿀 수 있고, 그 파일은 DiskInternals Linux Reader에서 읽을 수 있다. 이렇게 해서 framework-res.apk를 추출했고, 그 파일의 sha1sum은 b92dd7bd... 이였다.

* 그리고 d6ff2a17...은 업데이트 적용 후의 sha1sum인 것 같다.

* OTA 파일에서 patch/system/framework/framework-res.apk.p가 바이너리 패치 파일인 것 같다.

* apply_patch_check가 정확히 무슨 일을 하는지 모르겠다. 내 시스템에서 framework-res.apk의 sha1sum은 분명히 문제가 없다. 그리고 OTA 파일도 아마 문제가 없을 것이다. 정상적인 방법(sideload 말고)을 이용했을 때도 같은 에러가 발생했으며, 에러 메시지에서 보이는 파일명(zip 파일)은 sideload를 위해 다운 받은 zip 파일의 파일명과 일치하기 때문이다.

안드로이드 adb를 설치하고 사용하는 방법

1. SDK 설치

여기를 클릭하여 Android SDK에 접속하여, 필요한 프로그램을 다운받아 설치해야 한다. 참고로 ADT bundle이라고 되어 있는 것은 이런 저런 프로그램이 통합되어 있어서 용량이 크다. 앱을 개발할 생각이 없다면 SDK tools only라고 되어 있는 것을 다운받아서 설치해도 된다. 본인에게 맞는 방법으로 설치하자. 참고로 JDK도 설치해야 된다. System requirements에 자세히 적혀 있다.


SDK 설치가 완료되면 Android SDK Manager를 실행하고 Tools/Android SDK Platform-tools를 설치한다. 앱을 개발할 계획이 없다면 Android 4.3 (API 18) 등은 설치하지 않아도 된다.



2. USB 드라이버 설치

단순히 파일 복사만 하는 경우에는 드라이버를 설치하지 않아도 되지만, USB 디버깅을 하려면 추가 드라이버를 설치해야 한다. 이 드라이버는 제품에 따라 다운 받는 위치가 다르다. 이 글에서는 윈도우에서 넥서스 7 (2013)을 사용하는 경우를 기준으로 설명하겠다. 그 이외의 상황이라면 윈도우를 쓰는 경우에는 win-usb.html 또는 oem-usb.html을 참고하고, 다른 운영체제를 쓰는 경우에는 device.html을 참고하자.

Android SDK Manager를 실행하고 Extras/Google USB Driver를 설치한다. 앱을 개발할 계획이 없다면 Android 4.3 (API 18) 등은 설치하지 않아도 된다.

그 다음에 윈도우의 장치 관리자를 열고 기타 장치에서 느낌표가 떠 있는 Nexus 7을 선택하여 드라이버 업데이트를 한다. 수동으로 설치하는 옵션을 선택하자. 그 다음 드라이버를 검색할 위치를 지정해야 한다. 이 위치를 C:\Program Files\Android\android-sdk\extras\google\usb_driver으로 지정한다. (정확한 위치는 android-sdk를 설치한 위치에 따라 알맞게 수정.)

설치가 제대로 되었는지 확인하려면 cmd 창에서 adb devices 명령을 내려보고 기기가 나타나는지 보면 된다. adb가 기본적으로 PATH에 없으므로 PATH를 수정하든가 C:\Program Files\Android\android-sdk\platform-tools에서 cmd를 열어야 한다.

3. Recovery 모드에서 adb 사용

USB 코드가 달라서 드라이버를 또 설치해야 한다. 방법은 위와 비슷한데, 드라이버를 검색하는 옵션 대신 드라이버 목록에서 직접 선택하는 옵션을 사용해야 한다. 그렇게 하지 않으면 설치가 안 된다. (수동 설치 -> 직접 선택 -> (모든 장치) -> 디스크 있음 -> Andorid ADB Interface 선택)




2013년 8월 10일 토요일

Create a pivot table using SQL

이글을 참고하면 좋다: http://stackoverflow.com/a/12599372
링크한 글에서는 MAX()를 사용하고 있는데 경우에 따라 SUM()이 필요할 수도 있을 것 같다.

SQLite 같은 프로그램은 @sql같은 것을 지원하지 않지만, query를 여러번에 나누어서 수행하면 된다.

Scrollable Table with Fixed Header

HTML/CSS만 사용하여 머리글(첫 행)이 고정된 표를 만들고 싶은 경우가 있다. 이것은 해결하는 방법은 여러 가지가 있는데, 그 중 하나는 표를 두 개 만드는 방법이다. 이 방법을 간단하게 설명하면, 이 방법은 머리글만 포함하는 표와 머리글 없이 내용만 포함하는 표를 각각 만들어서 위아래로 붙여 놓는 방법이다. 그러나 이렇게 할 경우 첫번째 문제는 겉보기에는 두 개의 표가 하나로 보이지만 실제로는 각각의 표가 별개의 객체로 존재하게 되기 때문에, 머리글과 내용 사이의 논리적인 연관성을 표현하기 어려워진다는 것이다. 그리고 이것보다 더 현실적인 문제도 있는데, 이 문제는 열의 너비를 강제로 지정하지 않을 경우 위의 표와 아래의 표의 열 너비가 서로 일치하지 않게 될 수 있다는 것이다.

아무튼 원하는 요구 사항은 다음과 같다.
  • 하나의 table tag를 사용할 것
  • HTML/CSS만을 사용할 것
  • 열 너비를 강제로 지정하지 않아도 사용 가능하게 할 것
  • 테이블의 border가 변경되어도 머리글이 어긋나지 않을 것
인터넷을 검색하여 이런 방법을 찾았다. http://salzerdesign.com/test/fixedTable.html
아니면 이런 글도 있는데 이건 원리를 모르겠다.
 http://www.imaputz.com/cssStuff/bigFourVersion.html

그런데 위에서 링크한 방법은 열 너비를 맞추기 위해 머리글을 중복으로 넣어야 한다. 이렇게 하는 것이 조금 걸려서 내가 나름대로 다시 만들어 보았다. 원하는 박스가 정확한 위치에 있는지 쉽게 알아 보기 위해 일부러 border를 크게 만들어둔 상태이다. 실제 사용할 경우에는 약간 고쳐서 쓰면 될 것이다. 다음 링크에서 코드와 결과를 볼 수 있다. (http://jsfiddle.net/x72V3/3/) 그리고 남아 있는 문제점은 다음과 같다.
  • container에 가로 스크롤바가 발생할 경우, 내용만 좌우로 스크롤 되고 머리글은 좌우로 스크롤 되지 않는다. 이것은 position을 absolute로 했기 때문에 그렇다. 이 문제를 해결하기 위해 conationer를 하나 더 만드는 방법이 있긴 한데, 이렇게 하면 세로 스크롤바가 이상한 곳으로 숨어 버린다. (http://jsfiddle.net/JGeMg/3/)

2013년 8월 7일 수요일

Git subtree를 이용한 작업

다음과 같은 상황을 생각해보자. 현재 프로젝트 디렉토리 구조는 다음과 같다.
myproject/
        .git/
        app1/
                app1-files
        app2/
        others
그런데 여기서 app1만 떼어내서 프로젝트를 새로 만들고 싶다. 그리고 git 히스토리는 최대한 유지하고 싶다.
project-app1/
        .git/
        app1/
                app1-files

스택오버플로우에서 비슷한 질문을 찾았다.
http://stackoverflow.com/questions/359424/detach-subdirectory-into-separate-git-repository

처음에는 추천수를 가장 많이 받은 방법을 따라해보았다. (내가 실수해서 그렇게 되었을 가능성도 있지만) 저 방법을 그대로 따라하니 다음과 같이 되었다.
project-app1/
        .git/
        app1-files
그래서 디렉토리 구조를 또 바꿔야 하는데 이것도 filter-branch를 잘 쓰면 가능하겠지만 방법을 찾기 어려웠다. 어떻게 하다보니 찾게된 방법이 subtree를 이용하고 있었다.
http://stackoverflow.com/questions/1425892/how-do-you-merge-two-git-repositories

그래서 그냥 처음부터 subtree만 써서 다시 작업을 하면 좋겠다는 생각이 들었다. 최신 버전의 git을 설치하는 것도 문제인데 여기엔 적지 않겠다. (경우에 따라 소스를 직접 받아서 컴파일해야 할 수도 있다.)

디렉토리 분리

먼저 app1 디렉토리를 분리하는 여기를 참고해서 다음과 같이 하면 된다.
cd ~/path/myproject
git subtree split -P app1 -b app1-only
cd ~/path
여기서 -P 다음엔 디렉토리 이름을 적고, -b 다음에는 branch 이름을 적당히 적으면 된다.
mkdir ~/path/app1
cd ~/path/app1
git init
git pull ~/path/myproject app1-only
이렇게 하면 ~/path/app1 디렉토리에 app1의 내용만 분리된다. 원래의 myprojcet 디렉토리에서 app1을 삭제하는 방법은 참고한 글에 나온다. 그리고 참고한 글에 적힌 remote add는 생략한다.

디렉토리 가져오기

이제 디렉토리를 새로 만들어서 app1을 집어 넣어야 한다. 이것은 여기를 참고하였다. 다만 git subtree add를 하기 전에 뭔가 commit을 해두어야만 하는 것 같다.
mkdir ~/path/project-app1
cd ~/path/project-app1
git init
git add something
git commit something
git subtree add --prefix app1 ~/path/app1 master
이렇게 하면 처음에 원했던 작업이 완료된다. 다만 app1/somefile을 수정한 후 subtree add 이전의 커밋과 비교하는 것은 불가능하다. 처음 디렉토리에 대한 상대 경로가 변경되어서 그런 것 같다.

전체 히스토리에서 파일 삭제

생각을 더 해봤는데 더 좋은 방법이 있는 것 같다. 일단 myproject를 통채로 복사하고 디렉토리 이름을 project-app1으로 바꾼다. 이 디렉토리는 .git의 상위 디렉토리이므로 이름을 마음대로 바꿀 수 있다. 그리고 project-app1 디렉토리 내에서 불필요한 파일과 그에 해당하는 히스토리를 통채로 삭제해 버리면 된다. 이렇게 하는 방법은 다음 글에 적혀 있다.

2013년 6월 1일 토요일

Linux Commands

Advanced Bash-Scripting Guide에 Linux commands를 정리해둔 챕터가 있다. 다음 명령에 대해 정리되어 있다. 참고로 굵은 글씨는 필자가 마음대로 표시한 것으로 원본과는 무관하다.

. (See also source) ac adduser agetty agrep ar arch at autoload awk (See also Using awk for math operations) badblocks banner basename batch bc bg bind bison builtin bzgrep bzip2 cal caller cat cd chattr chfn chgrp chkconfig chmod chown chroot cksum clear clock cmp col colrm column comm command compgen complete compress coproc cp cpio cron crypt csplit cu cut date dc dd debugfs declare depmod df dialog diff diff3 diffstat dig dirname dirs disown dmesg doexec dos2unix du dump dumpe2fs e2fsck echo egrep enable enscript env eqn eval exec exit (Related topic: exit status) expand export expr factor false fdformat fdisk fg fgrep file find finger flex flock fmt fold free fsck ftp fuser getfacl getopt getopts gettext getty gnome-mount grep groff groupmod groups (Related topic: the $GROUPS variable) gs gzip halt hash hdparm head help hexdump host hostid hostname (Related topic: the $HOSTNAME variable) hwclock iconv id (Related topic: the $UID variable) ifconfig info infocmp init insmod install ip ipcalc iptables iwconfig jobs join jot kill killall last lastcomm lastlog ldd less let lex lid ln locate lockfile logger logname logout logrotate look losetup lp ls lsdev lsmod lsof lspci lsusb ltrace lynx lzcat lzma m4 mail mailstats mailto make MAKEDEV man mapfile mcookie md5sum merge mesg mimencode mkbootdisk mkdir mke2fs mkfifo mkisofs mknod mkswap mktemp mmencode modinfo modprobe more mount msgfmt mv nc netconfig netstat newgrp nice nl nm nmap nohup nslookup objdump od openssl passwd paste patch (Related topic: diff) pathchk pax pgrep pidof ping pkill popd pr printenv printf procinfo ps pstree ptx pushd pwd (Related topic: the $PWD variable) quota rcp rdev rdist read readelf readlink readonly reboot recode renice reset resize restore rev rlogin rm rmdir rmmod route rpm rpm2cpio rsh rsync runlevel run-parts rx rz sar scp script sdiff sed seq service set setfacl setquota setserial setterm sha1sum shar shopt shred shutdown size skill sleep slocate snice sort source sox split sq ssh stat strace strings strip stty su sudo sum suspend swapoff swapon sx sync sz tac tail tar tbl tcpdump tee telinit telnet tex texexec time times tmpwatch top touch tput tr traceroute true tset tsort tty tune2fs type typeset ulimit umask umount uname unarc unarj uncompress unexpand uniq units unlzma unrar unset unsq unzip uptime usbmodules useradd userdel usermod users usleep uucp uudecode uuencode uux vacation vdir vmstat vrfy w wait wall watch wc wget whatis whereis which who whoami whois write xargs yacc yes zcat zdiff zdump zegrep zfgrep zgrep zip


  1. http://tldp.org/LDP/abs/html/part4.html