ラベル gawk の投稿を表示しています。 すべての投稿を表示
ラベル gawk の投稿を表示しています。 すべての投稿を表示

2019年11月29日金曜日

シェル芸で audit ログに分かり易いタイムスタンプを付加

audit ログというのは、めったには見ないのですが、タイムスタンプが UNIX 時間になっていて不便です。前回の dmesg に続いて、分かり易いタイムスタンプを付加してみました。
[root@hoge ~]# gawk -F\( '{print strftime("%F %T",$2),$0}' /var/log/audit/audit.log
...
2019-11-29 06:26:01 type=SERVICE_STOP msg=audit(1574976361.151:1341): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset"
2019-11-29 06:27:01 type=SERVICE_START msg=audit(1574976421.151:1342): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset"
2019-11-29 06:27:01 type=SERVICE_STOP msg=audit(1574976421.151:1343): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=sysstat-collect comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset"
[root@hoge ~]# 
厳密には $2 をピリオド (.) または コロン (:) のところまででカット (1574976421.151:1343 -> 1574976421) してから、strftime に渡すのが「お行儀が良い」ものと思いますが、AWK の仕様を考えれば、そのまま $2 を渡すで良いものと思います。もっと明示的に、0+$2 と記述することもできますが、シェル芸 (gawk芸?) 道的には、そのまんま $2 指定でしょう。
[root@hoge ~]# date ; gawk -F\( '{printf("%d %s\n",0+$2,$0)}' /var/log/audit/audit.log | tail -1
2019年 11月 29日 金曜日 06:40:32 JST
1574977201 type=SERVICE_STOP msg=audit(1574977201.368:1377): pid=1 uid=0 auid=4294967295 ses=4294967295 msg='unit=dnf-makecache comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'UID="root" AUID="unset"
[root@hoge ~]# date -d @1574977201
2019年 11月 29日 金曜日 06:40:01 JST

2019年11月27日水曜日

シェル芸で dmesg に分かり易いタイムスタンプを付加してみたが・・・

ふと思い付きで、dmesg の左端のタイムスタンプを分かり易くできるのでは、と閃いた。。。
[root@hoge ~]# (date -d"$(uptime -s)" +%s;dmesg)|awk -F\[ 'BEGIN {getline b} {print strftime("%F %T",b+$2),$0}'
...
2019-11-27 21:46:52 [52976.500320] IPv6: ADDRCONF(NETDEV_UP): wlp4s0: link is not ready
2019-11-27 21:47:10 [52994.337872] [drm:intel_pipe_update_end [i915]] *ERROR* Atomic update failure on pipe B (start=92367 end=92368) time 177 us, min 1073, max 1079, scanline start 1069, end 1077
2019-11-27 21:47:11 [52995.637878] [drm:intel_pipe_update_end [i915]] *ERROR* Atomic update failure on pipe B (start=92445 end=92446) time 174 us, min 1073, max 1079, scanline start 1068, end 1079
しかしながら、そもそも dmesg のオプションに、所望の機能があるのではないかと、ヘルプを見てみたら。。。ありました。
[root@hoge ~]# dmesg -e
...
[11月27 21:46] IPv6: ADDRCONF(NETDEV_UP): wlp4s0: link is not ready
[11月27 21:47] [drm:intel_pipe_update_end [i915]] *ERROR* Atomic update failure on pipe B (start=92367 end=92368) time 177 us, min 1073, max 1079, scanline start 1069, end 1077
[  +1.300006] [drm:intel_pipe_update_end [i915]] *ERROR* Atomic update failure on pipe B (start=92445 end=92446) time 174 us, min 1073, max 1079, scanline start 1068, end 1079
知らなかった。/var/log/messages を見て、対応する行を探してました。この機会に、頭のノートにメモっておこう。

2019年10月28日月曜日

最近発見された3つの立方数の和が42になる数

掲題の件を CentOS8 の gawk で確認してみた。
-M オプション(MPFR / MP 拡張)が必要なので、CentOS7 以下では駄目でした。
[root@hoge ~]# uname -a
Linux hoge 4.18.0-80.el8.x86_64 #1 SMP Wed Mar 13 12:02:46 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
[root@hoge ~]# gawk --version
GNU Awk 4.2.1, API: 2.0 (GNU MPFR 3.1.6-p2, GNU MP 6.1.2)
Copyright (C) 1989, 1991-2018 Free Software Foundation.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
[root@hoge ~]# cat 42.gawk 
BEGIN {
 a = -80538738812075974
 b =  80435758145817515
 c =  12602123297335631

 printf("a = %18d    length=%d\n", a, length(-a))
 printf("b = %18d    length=%d\n", b, length(b))
 printf("c = %18d    length=%d\n", c, length(c))
 print ""

 x = a^3
 y = b^3
 z = c^3

 printf("a^3 = %52d    length=%d\n", x, length(-x))
 printf("b^3 = %52d    length=%d\n", y, length(y))
 printf("c^3 = %52d    length=%d\n", z, length(z))
 print ""

 printf("a^3 + b^3 + c^3 = %d\n", x + y + z)

 exit(0)
}
[root@hoge ~]# time gawk -M -f 42.gawk 
a = -80538738812075974    length=17
b =  80435758145817515    length=17
c =  12602123297335631    length=17

a^3 = -522413599036979150280966144853653247149764362110424    length=51
b^3 =  520412211582497361738652718463552780369306583065875    length=51
c^3 =    2001387454481788542313426390100466780457779044591    length=49

a^3 + b^3 + c^3 = 42

real 0m0.002s
user 0m0.000s
sys 0m0.001s
恐ろしい桁数ですが、このように計算は一瞬でした。

2019年5月6日月曜日

シェルスクリプトでファイルサイズを取得するベストな方法は?

シェルスクリプトでファイルサイズを取得するのに、今まで次のように書いていて、常套句と思っていました。
[root@hoge tmp]# uname -a
Linux hoge 3.10.0-957.5.1.el7.x86_64 #1 SMP Fri Feb 1 14:54:57 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
[root@hoge tmp]# ls -l /etc/services 
-rw-r--r-- 1 root root 670293 Jun  7  2013 /etc/services
[root@hoge tmp]# declare -i fsize=`wc -c /etc/services`
bash: declare: 670293 /etc/services: division by 0 (error token is "/services")
[root@hoge tmp]# echo $fsize

[root@hoge tmp]# wc -c /etc/services 
670293 /etc/services
[root@hoge tmp]# declare -i fsize=`wc -c /etc/services | gawk '{print $1}'`
[root@hoge tmp]# echo $fsize
670293
gawk まで呼び出すのがイマイチだなとは思っていたのですが、本日ふと思い立ち、調べてみたら先人の方が居られました。
https://ameblo.jp/archive-redo-blog/entry-10196055325.html
なるほど標準入力にリダイレクトすれば1コマンドで済むのですね。賢い方法と思いました。
[root@hoge tmp]# declare -i fsize=`wc -c < /etc/services`                    
[root@hoge tmp]# echo $fsize
670293
これからは、このパターンを使おうと思います。
ところで、wc というコマンド名からは、ファイルを全部読んでファイルサイズを得る動きをしそうに見えますが、そこは賢い実装になっており、-c オプション指定だと fstat(2) システムコールが利用され、ファイルを全部読み出すなどという非効率な振舞いにはならないようです。
[root@hoge tmp]# strace wc -c < /etc/services
execve("/usr/bin/wc", ["wc", "-c"], [/* 46 vars */]) = 0
brk(NULL)                               = 0x1e76000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf32f000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=90399, ...}) = 0
mmap(NULL, 90399, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa4cf318000
close(3)                                = 0
open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340$\2\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=2151672, ...}) = 0
mmap(NULL, 3981792, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa4ced42000
mprotect(0x7fa4cef04000, 2097152, PROT_NONE) = 0
mmap(0x7fa4cf104000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c2000) = 0x7fa4cf104000
mmap(0x7fa4cf10a000, 16864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf10a000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf317000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf315000
arch_prctl(ARCH_SET_FS, 0x7fa4cf315740) = 0
mprotect(0x7fa4cf104000, 16384, PROT_READ) = 0
mprotect(0x608000, 4096, PROT_READ)     = 0
mprotect(0x7fa4cf330000, 4096, PROT_READ) = 0
munmap(0x7fa4cf318000, 90399)           = 0
brk(NULL)                               = 0x1e76000
brk(0x1e97000)                          = 0x1e97000
brk(NULL)                               = 0x1e97000
fstat(0, {st_mode=S_IFREG|0644, st_size=670293, ...}) = 0
lseek(0, 0, SEEK_CUR)                   = 0
lseek(0, 0, SEEK_END)                   = 670293
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf32e000
write(1, "670293\n", 7670293
)                 = 7
close(0)                                = 0
close(1)                                = 0
munmap(0x7fa4cf32e000, 4096)            = 0
close(2)                                = 0https://ameblo.jp/archive-redo-blog/entry-10196055325.html
exit_group(0)                           = ?
+++ exited with 0 +++
[root@hoge tmp]# 
ということで、これがベストな方法に思いましたが、他にあるでしょうかね?
もちろん Perl/Python/Ruby等 の汎用スクリプト言語を呼べば同様のことが出来るけど、軽量に行うには wc -c < file がベストなのではと思っています。

2019-07-24追記
stat -c %s というのもありますが、当然 -c %s を解釈する処理の分だけ遅いに違いないと思っていましたが、一応実験してみました。
[root@hoge ~]# perf stat stat -c %s /etc/services
670293

 Performance counter stats for 'stat -c %s /etc/services':

          0.728356      task-clock (msec)         #    0.749 CPUs utilized          
                 2      context-switches          #    0.003 M/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
               249      page-faults               #    0.342 M/sec                  
         2,528,856      cycles                    #    3.472 GHz                    
         1,292,306      instructions              #    0.51  insn per cycle         
           252,891      branches                  #  347.208 M/sec                  
            11,528      branch-misses             #    4.56% of all branches        

       0.000972916 seconds time elapsed

[root@hoge ~]# perf stat wc -c < /etc/services
670293

 Performance counter stats for 'wc -c':

          0.599273      task-clock (msec)         #    0.705 CPUs utilized          
                 2      context-switches          #    0.003 M/sec                  
                 0      cpu-migrations            #    0.000 K/sec                  
               219      page-faults               #    0.365 M/sec                  
         2,077,769      cycles                    #    3.467 GHz                    
         1,043,855      instructions              #    0.50  insn per cycle         
           202,792      branches                  #  338.397 M/sec                  
            10,808      branch-misses             #    5.33% of all branches        

       0.000849638 seconds time elapsed

2016年1月23日土曜日

gawk で文字列 "01" の比較でハマった

長年(20年以上) AWK を使っていて、わかってるつもりでしたが、文字列が暗黙に数値として扱われる際の落とし穴にハマりましたので、備忘録です。以前にも、このパターンに悩まされた記憶があるんですが、忘れたころにふたたびバグってしまいました。
BEGIN {
    s="01 02"
    split(s, ss)
}
{
    for (i in ss) {
        if ($1 == ss[i]) {
            printf "%s == %s\n", $1, ss[i]
        } else {
            printf "%s != %s\n", $1, ss[i]
        }
    }
}
[root@hoge tmp]# echo 01 | gawk -f test_string_01.awk 
01 == 01
01 != 02
[root@hoge tmp]# echo 1 | gawk -f test_string_01.awk 
1 == 01
1 != 02
$1 が 1 の場合には、if ($1 == ss[i]) において ss[i] が数値として扱われ、文字列の "01" が暗黙に数値の 1 として比較が実行されるのだと思います。次のように修正(C言語のキャストっぽく修正)することで、意図した動作になりました。
BEGIN {
    s="01 02"
    split(s, ss)
}
{
    for (i in ss) {
        if ($1 == ""ss[i]) {
            printf "%s == %s\n", $1, ss[i]
        } else {
            printf "%s != %s\n", $1, ss[i]
        }
    }
}
[root@hoge tmp]# diff -u test_string_01.awk test2_string_01.awk 
--- test_string_01.awk 2016-01-23 20:06:54.537647508 +0900
+++ test2_string_01.awk 2016-01-23 20:25:23.543167642 +0900
@@ -4,7 +4,7 @@
 }
 {
     for (i in ss) {
-        if ($1 == ss[i]) {
+        if ($1 == ""ss[i]) {
             printf "%s == %s\n", $1, ss[i]
         } else {
             printf "%s != %s\n", $1, ss[i]
[root@hoge tmp]# echo 01 | gawk -f test2_string_01.awk 
01 == 01
01 != 02
[root@hoge tmp]# echo 1 | gawk -f test2_string_01.awk 
1 != 01
1 != 02
ちなみに、別実装(nawk, mawk)でも、同様の結果でした。
[root@hoge tmp]# echo 01 | nawk -f test_string_01.awk 
01 != 02
01 == 01
[root@hoge tmp]# echo 1 | nawk -f test_string_01.awk 
1 != 02
1 == 01
[root@hoge tmp]# echo 01 | mawk -f test_string_01.awk 
01 != 02
01 == 01
[root@hoge tmp]# echo 1 | mawk -f test_string_01.awk 
1 != 02
1 == 01
nawk, mawk では、for (i in ss) の順序が、gawk とは違うようですが、今回の問題の比較部分は同様に意図しない動作になります。そして、同じ修正で、意図した動作になります。
[root@hoge tmp]# echo 1 | mawk -f test2_string_01.awk 
1 != 02
1 != 01
[root@hoge tmp]# echo 1 | nawk -f test2_string_01.awk 
1 != 02
1 != 01

こういうことも、たまにはあるけども、いやー AWK って本当にいいもんですね。って思います。
この 20年 どんだけお世話になったことか。費用対効果(学習コストに対する成果)が抜群じゃないかなと。手短に手早く書いて、あっという間に結果を得られることがしばしばです。

2011年11月27日日曜日

mawk は確かに速い(2倍くらい)

AWK Users JP の次の記事を読んで、手持ちのよく使う awk スクリプトを mawk で実行してみたところ、確かに速かったです。軒並み2倍速かった。

awk のパフォーマンス

試しは、Fedora 16 上で行いましたが、常用している CentOS 5 (or RHEL5) でも簡単に利用できるかどうか EPEL を見てみたら、有難いことに提供されてました。
というわけで、まず、インストールを。
[root@centos5 ~]# uname -a
Linux centos5 2.6.18-274.7.1.el5 #1 SMP Thu Oct 20 16:21:01 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux
[root@centos5 ~]# yum install mawk --enablerepo=epel
Loaded plugins: downloadonly, fastestmirror
Loading mirror speeds from cached hostfile
 * base: www.ftp.ne.jp
 * epel: ftp.jaist.ac.jp
 * extras: www.ftp.ne.jp
 * updates: www.ftp.ne.jp
Setting up Install Process
Resolving Dependencies
--> Running transaction check
---> Package mawk.x86_64 0:1.3.4-5.20100625.el5 set to be updated
--> Finished Dependency Resolution

Dependencies Resolved

==========================================================================================
 Package         Arch              Version                          Repository       Size
==========================================================================================
Installing:
 mawk            x86_64            1.3.4-5.20100625.el5             epel            104 k

Transaction Summary
==========================================================================================
Install       1 Package(s)
Upgrade       0 Package(s)

Total download size: 104 k
Is this ok [y/N]: y
Downloading Packages:
mawk-1.3.4-5.20100625.el5.x86_64.rpm                               | 104 kB     00:00     
Running rpm_check_debug
Running Transaction Test
Finished Transaction Test
Transaction Test Succeeded
Running Transaction
  Installing     : mawk                                                               1/1 

Installed:
  mawk.x86_64 0:1.3.4-5.20100625.el5                                                      

Complete!
[root@centos5 ~]# 

次のテスト用の awk スクリプトは、a から zzzz までの文字列 (Linux の SCSI ディスク名の sdXX の XX 部分に使われている) を出力するものです。適度に重いかと。。
#
# Note: This awk script prints
#       a, b, ... z, aa, ab, ... zz, aaa, aab, ... zzz
#
function get_sdstr(n,   r,ret) {
        for (;;) {
                if (n <= 26) {
                        return letter[n]""ret

                } else {
                        r = n % 26 ; r = r ? r : 26
                        ret = letter[r]""ret
                        n = (n-r)/26
                }
        }
}

BEGIN {
        for (i=1; i <= 26; i++) {
                letter[i] = substr("abcdefghijklmnopqrstuvwxyz",i,1)
        }

        for (i=1; i <= (26+26*26+26*26*26+26*26*26*26); i++) {
                print get_sdstr(i)
        }
        exit(0)
}
これを、gawk と mawk でそれぞれ実行して、/usr/bin/time でパフォーマンス測定した結果が、次の通りです。
[root@centos5 ~]# md5sum test.awk 
ee228358d1513e48e0495e1e79f3956c  test.awk
[root@centos5 ~]# rpm -q gawk
gawk-3.1.5-14.el5
[root@centos5 ~]# rpm -q mawk
mawk-1.3.4-5.20100625.el5
[root@centos5 ~]# 
[root@centos5 ~]# /usr/bin/time gawk -f ./test.awk | md5sum
3.43user 0.01system 0:03.47elapsed 99%CPU (0avgtext+0avgdata 3824maxresident)k
0inputs+0outputs (0major+279minor)pagefaults 0swaps
a9de67bf77dec1b5285ee27f71ab3564  -
[root@centos5 ~]# 
[root@centos5 ~]# /usr/bin/time mawk -f ./test.awk | md5sum
1.48user 0.00system 0:01.49elapsed 99%CPU (0avgtext+0avgdata 2976maxresident)k
0inputs+0outputs (0major+220minor)pagefaults 0swaps
a9de67bf77dec1b5285ee27f71ab3564  -
このように、2倍くらい速いです。
まあ、処理内容によるでしょうけど、わたしが日頃使う手持ちスクリプトは軒並み2倍速かったので、これからは有難く常用させてもらおうと思います。作者さん&メンテナー様に感謝。

EPEL の使い方については、次の記事を参照ください。
CentOS 6 で ntfs をマウントする
なお、CentOS 6 (or RHEL6) 用の EPEL チャネルにも mawk ありました。

gawk で性能足りないということがあったら、最後の切り札に使える場合があるかも。ただし、GNU 拡張等、互換性に注意する必要がある。

2011年3月5日土曜日

gawkで配列の要素数を得る方法

gawk で配列の要素数を得る場合 len=0 ; for (e in a) len++ のように書いていました。
しかし、perl なら @a か $#a+1 、bash なら ${#a[@]} 、Ruby なら a.size または a.length などと書けるし、もしかして gawk でも簡単に記述できるのでは?と思って、man を見たところ、gawk-3.1.5 以降であれば、length(a) と書けることを知りました。
ただ、わたしの場合、仕事上、古いバージョンもサポートする必要があり、使えないのですが、ここにメモしておきます。

まずは、man gawk(1) から抜粋です。
       length([s])             Returns the length of the string s, or the length of  $0
                               if s is not supplied.  Starting with version 3.1.5, as a
                               non-standard extension, with an array argument, length()
                               returns the number of elements in the array.
次に、テストスクリプトです。
#!/bin/gawk -f
#
# test_length_array.gawk
#
# memo:
#   length(array) returns the number of elements with gawk-3.1.5 or later
#   see man gawk(1)
#
function my_len(a,      len) {
        len=0
        for (i in a) len++
        return len
}
function chk_support_length_for_array() {
        return system("gawk 'BEGIN {a[1]=1;length(a);exit(0)}' >/dev/null 2>&1")
}
BEGIN {
        for (i=100; i<777+100; i++) {
                a[i]=i
        }
        if (PROCINFO["version"] == "") {
                f="gawk --version" ; f | getline ; ver=$3 ; close(f)
                printf "INFO: gawk-%s does not supports PROCINFO[\"version\"]\n", ver
        } else {
                ver=PROCINFO["version"]
                printf "INFO: gawk-%s supports PROCINFO[\"version\"]\n", ver
        }
        if (chk_support_length_for_array()) {
                printf "WARNING: gawk-%s does not supports length(array)\n", ver
        }
        printf "my_len(a)=%d\n", my_len(a)
        printf "length(a)=%d\n", length(a)
        exit(0)
}
配列に対する length をサポートするか確認する関数も書いてみました。あと、これも知らなかったのですが、gawk-3.1.4 以降であれば、PROCINFO["version"] という組み込み変数を使えるようです。これを、Fedora 14 で実行してみると、次のようになります。
[root@fedora14 ~]# ./test_length_array.gawk 
INFO: gawk-3.1.8 supports PROCINFO["version"]
my_len(a)=777
length(a)=777
古いシステムだと、次のようにエラーになります。
# ./test_length_array.gawk 
INFO: gawk-3.0.6 does not supports PROCINFO["version"]
WARNING: gawk-3.0.6 does not supports length(array)
my_len(a)=777
gawk: ./test_length_array.gawk:33: fatal: attempt to use array `a' in a scalar context

2010年3月22日月曜日

ソースコードの行数カウント

bash や awk スクリプトのソースコード行数を計測したかったため、どこかにいいのが無いかなと google で探したが、見当たらず。
#「コロ助」という Windows 上で動くものはありましたが。

空行とコメント行を考慮できればいい程度なので、awk で書いてみました。
# cat count.gawk 
{
        line++
}
/^[[:blank:]]*$/ {
        space++
}
/^[[:blank:]]*#/ {
        comment++
}
END {
        effect = line - (space + comment)
        printf "%5d  %5d  %5d  %5d  %s\n",
                effect, comment, space, line, FILENAME
}
# gawk -f count.gawk /etc/init.d/kdump
  378     43     49    470  /etc/init.d/kdump
まあ、この程度でも十分。
人気ブログランキングへ にほんブログ村 IT技術ブログへ