end0tknr's kipple - web写経開発

太宰府天満宮の狛犬って、妙にカワイイ

JSON for perl ? における 文字列(string) or 数値(numeric, integer)の判別方法

サーバからjsonを受け取った javascript が、 数値(例:2)を期待し厳密等価演算子 (===)でvalidateしたところ、 文字列(例:"2")だった為、false となったことがきっかけです。

perl製サーバアプリとしては、$val += 0 により、数値化( numfy )しましたが、 数値と文字列を区別なく扱えるperlで、JSON.pm は、 どのようにして、文字列(string) or 数値(numeric, integer)の判別しているのでしょう?

JSON for perl は、文字列 or 数値を判別し、json

#!/usr/local/bin/perl
use strict;
use JSON;

main();
sub main {
    print JSON::encode_json({val=>'10'}),"\n";
    print JSON::encode_json({val=>10}),"\n";
}
1;

↑こう書くと、↓こう出力されます

$ ./test_encode_json.pl 
{"val":"10"}
{"val":10}

JSON from perl のドキュメントには文字列 or 数値を判別できる旨が記載

http://search.cpan.org/perldoc?JSON に次のように記載されていますが、 一体、どのように実装されているのでしょう?

number A JSON number becomes either an integer, numeric (floating point) or string scalar in perl, depending on its range and any fractional parts. On the Perl level, there is no difference between those as Perl handles all the conversion details, but an integer may take slightly less memory and might represent more values exactly than floating point numbers.

If the number consists of digits only, JSON will try to represent it as an integer value. If that fails, it will try to represent it as a numeric (floating point) value if that is possible without loss of precision. Otherwise it will preserve the number as a string value (in which case you lose roundtripping ability, as the JSON number will be re-encoded to a JSON string).

JSONのバックエンドにある JSON::PP は B moduleを利用

JSONは、バックエンドに JSON::XSまたはJSON::PP を使用しますが JSON::PPはB moduleを利用して、数値or文字列を判別しています。

具体的には、B for perlを利用して、 B::SVp_IOK , B::SVp_NOK , B::SVp_POK とビット演算することで判別しています。

perlスカラー値には、整数 (IV)、符号なし整数 (UV)、 倍精度 (NV)、文字列 (PV)、他スカラ (SV) があります。

sub value_to_json {
    my ($self, $value) = @_;

    return 'null' if(!defined $value);

    my $b_obj = B::svref_2object(\$value);  # for round trip problem
    my $flags = $b_obj->FLAGS;
    ######## HERE !!!! ########
    return $value # as is 
        if $flags & ( B::SVp_IOK | B::SVp_NOK ) and !( $flags & B::SVp_POK ); # SvTYPE is IV or NV?

    my $type = ref($value);

    if(!$type){
        return string_to_json($self, $value);
    }
    elsif( blessed($value) and  $value->isa('JSON::PP::Boolean') ){
        return $$value == 1 ? 'true' : 'false';
    }
    elsif ($type) {
        if ((overload::StrVal($value) =~ /=(\w+)/)[0]) {
            return $self->value_to_json("$value");
        }

        if ($type eq 'SCALAR' and defined $$value) {
            return   $$value eq '1' ? 'true'
                   : $$value eq '0' ? 'false'
                   : $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ? 'null'
                   : encode_error("cannot encode reference to scalar");
        }

         if ( $self->{PROPS}->[ P_ALLOW_UNKNOWN ] ) {
             return 'null';
         }
         else {
             if ( $type eq 'SCALAR' or $type eq 'REF' ) {
                encode_error("cannot encode reference to scalar");
             }
             else {
                encode_error("encountered $value, but JSON can only represent references to arrays or hashes");
             }
         }

    }
    else {
        return $self->{fallback}->($value)
             if ($self->{fallback} and ref($self->{fallback}) eq 'CODE');
        return 'null';
    }

}

http://search.cpan.org/perldoc?JSON%3A%3APP

自分で、文字列(string) or 数値(numeric, integer)を判別するには?

次のように書けはOKです

#!/usr/local/bin/perl
use strict;
use B ();

main();
sub main {

    for my $value (10, "10", 10.0,  10.1, "10"){
        my $b_obj = B::svref_2object(\$value);
        my $flags = $b_obj->FLAGS;
        my $comp_1 = ($flags & ( B::SVp_IOK | B::SVp_NOK )),"\n";
        my $comp_2 =  ( $flags & B::SVp_POK ),"\n";
        if( $comp_1 and not $comp_2){
            print "$value is NUMERIC\n";
        } else {
            print "$value is            STRING\n";
        }
    }
}

install redmine + nginx + unicorn

前準備 - 必要moduleのinstall

# yum groupinstall "Development Tools"
# yum install openssl-devel readline-devel zlib-devel curl-devel \
      libyaml-devel ImageMagick ImageMagick-devel
# yum install ipa-pgothic-fonts
# yum install ruby ruby-devel

install redmine

と言っても、wgetして解凍するだけ

$ cd ~/dev
$ wget http://www.redmine.org/releases/redmine-3.3.0.tar.gz
$ tar -zxvf redmine-3.3.0.tar.gz
$ ln -s redmine-3.3.0  redmine

redmine 用 database準備

mysql> create database redmine CHARACTER SET utf8;
mysql> GRANT ALL ON redmine.* to redmine@localhost;
mysql> FLUSH PRIVILEGES;
mysql> SET PASSWORD FOR redmine@localhost=password('????');

redmine 設定と、追加module install

db接続と、gmail smtpによるメール設定

$ cd ~/dev/redmine/redmine/config
$ cp database.yml.example database.yml
$ vi database.yml
production:
  adapter: mysql2
  database: redmine
  host: localhost
  username: redmine
  password: "????"
  encoding: utf8
  
$ cp configuration.yml.example configuration.yml
email_delivery:
  delivery_method: :smtp
  smtp_settings:
    enable_starttls_auto: true
    address: "smtp.gmail.com"
    port: 587
    domain: "smtp.gmail.com" 
    authentication: :plain
    user_name: "????@gmail.com"
    password: "????"
# gem install io-console
# gem install bundler --no-rdoc --no-ri
   ## --no-rdoc --no-ri はドキュメント不要のため
# gem install json
# yum install mysql-devel
# gem install mysql2

$ cd ~/dev/redmine
$ bundle install --path vendor/bundler --without development test
$ bundle exec rake generate_secret_token
$ bundle exec rake db:migrate RAILS_ENV=production

ruby application server - unicorn

$ ~/dev/redmine
$ vi Gemfile
gem "unicorn"   #<-ADD

$ bundle update

config unicorn

$ vi /home/end0tknr/dev/redmine/config/unicorn.rb

# -*- coding: utf-8 -*-
worker_processes 4
timeout 900

listen 6000
pid '/home/end0tknr/logs/unicorn.pid'

stderr_path '/home/end0tknr/logs/unicorn.log'
stdout_path '/home/end0tknr/logs/unicorn.log'

preload_app true
GC.respond_to?(:copy_on_write_friendly=) and GC.copy_on_write_friendly = true

before_fork do |server, worker|
defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect!

old_pid = "#{ server.config[:pid] }.oldbin"
unless old_pid == server.pid
  begin
   sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU
   Process.kill :QUIT, File.read(old_pid).to_i
   rescue Errno::ENOENT, Errno::ESRCH
  end
end
end

after_fork do |server, worker|
  defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection
end

config nginx

# vi /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;
    server_tokens off;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    include /etc/nginx/conf.d/*.conf;

    index   index.html index.htm;

   server {
     listen       80;
     location /favicon.ico {
       alias /home/ec2-user/dev/Splats/static/img/favicon.ico;
       break;
       access_log off;
     }

     location / {
       return 302 https://$host$request_uri;
     }
   }

  server {
    listen 443 ssl;
 
    ssl_certificate /etc/letsencrypt/live/????.????.mydns.jp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/????.????.mydns.jp/privkey.pem;
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
 
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
 
    root /usr/share/nginx/html;
 
    index index.html index.htm index.nginx-debian.html;

    allow ???.???.???.0/24;
    deny  all;
 
    server_name _;
        location /redmine {
            proxy_pass      http://127.0.0.1:6000;

            auth_basic "MEMBER ONLY";
            auth_basic_user_file /home/ec2-user/dev/htpasswd;

            proxy_set_header Host             $host;
            proxy_set_header X-Real-IP        $remote_addr;
            proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-User $remote_user;
        }
  }
}

start uncorn , nginx

「 ????.????.mydns.jp/redmine 」でアクセスする為、「 --path /redmine」を起動時に指定しています。

$ cd /home/ec2-user/dev/redmine
$ bundle exec unicorn_rails -D --path /redmine \
   -c config/unicorn.rb -E production

$ sudo su -
# /etc/rc.d/init.d/nginx start

access to https://????.????.mydns.jp/redmine
initial user'ss id/pw = admin/admin

後は、以下のurlを参照。

http://redmine.jp/tech_note/first-step/admin/

Net::SMTPS for perl による Gmail SMTP利用には、アプリパスワードが必要

end0tknr.hateblo.jp 以前↑このように書いて動作していた気がしますが、 googleに2段階認証が導入された為でしょううか? 動作しなくなっていたので、以下のように修正しました。

#!/usr/local/bin/perl
use strict;
use utf8;
use FindBin;
use File::Spec;
use lib File::Spec->catdir( $FindBin::Bin, '../lib' );
use Encode;
use Net::SMTPS;
use MIME::Base64;
use Data::Dumper;

my $SMTP_CONF = {
    host     => 'smtp.gmail.com',
    port     => '587',
    from     => 'ないしょ@gmail.com',
    auth_uid => 'ないしょ@gmail.com',

    ### NOTICE!! application password
    ### https://myaccount.google.com/security#signin
    ### https://support.google.com/mail/answer/14257
    auth_pw  => 'ここは、アプリパスワード'
};

main();

sub main {
    my $ssl = 'starttls';    # 'ssl' / 'starttls' / undef

    my $smtp = Net::SMTPS->new(
        $SMTP_CONF->{host},
        Port  => $SMTP_CONF->{port},
        doSSL => $ssl,
        Debug => 1
    );

    $smtp->auth( $SMTP_CONF->{auth_uid}, $SMTP_CONF->{auth_pw} )
        or die "can't login smtp server";

    my $mailto = ['ないしょ@gmail.com'];
    my $mailto_str = join( ',', @$mailto );

    my $subject_org = 'これはテストです';
    my $subject = Encode::encode( 'MIME-Header-ISO_2022_JP', $subject_org );

    my $message = <<EOF;
このメールはテストです
EOF

    #メールのヘッダーを構築
    my $header = << "MAILHEADER_1";
From: $SMTP_CONF->{from}
Return-path: $SMTP_CONF->{from}
Reply-To: $SMTP_CONF->{from}
To: $mailto_str
MAILHEADER_1

    $header .= <<"MAILHEADER_2";
Subject: $subject
Mime-Version: 1.0
Content-Type: text/plain; charset = "ISO-2022-JP"
Content-Transfer-Encoding: 7bit
MAILHEADER_2

    $message = encode( 'iso-2022-jp', $message );

    $smtp->mail( $SMTP_CONF->{from} );
    $smtp->to(@$mailto);
    $smtp->data();
    $smtp->datasend("$header\n");
    $smtp->datasend("$message\n");
    $smtp->dataend();
    $smtp->quit;
}

アプリパスワードでなく、通常?のgoogleのログインパスワードを使用すると次のようなエラーとなります。

$ ./test_send_mail_by_gmail_smtp.pl 
Net::SMTPS>>> Net::SMTPS(0.03)
Net::SMTPS>>>   IO::Socket::INET(1.33)
Net::SMTPS>>>     IO::Socket(1.36)
Net::SMTPS>>>       IO::Handle(1.34)
Net::SMTPS>>>         Exporter(5.68)
Net::SMTPS>>>   Net::SMTP(3.05)
Net::SMTPS>>>     Net::Cmd(3.05)
Net::SMTPS>>>     IO::Socket::IP(0.37)
Net::SMTPS=GLOB(0x2b41ae0)<<< 220 smtp.gmail.com ESMTP i69sm1748185pfk.30 - gsmtp
Net::SMTPS=GLOB(0x2b41ae0)>>> EHLO localhost.localdomain
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-smtp.gmail.com at your service, [61.21.205.219]
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-SIZE 35882577
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-8BITMIME
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-STARTTLS
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-ENHANCEDSTATUSCODES
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-PIPELINING
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-CHUNKING
Net::SMTPS=GLOB(0x2b41ae0)<<< 250 SMTPUTF8
Net::SMTPS=GLOB(0x2b41ae0)>>> STARTTLS
Net::SMTPS=GLOB(0x2b41ae0)<<< 220 2.0.0 Ready to start TLS
Net::SMTPS=GLOB(0x2b41ae0)>>> EHLO localhost.localdomain
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-smtp.gmail.com at your service, [61.21.205.219]
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-SIZE 35882577
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-8BITMIME
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-AUTH LOGIN PLAIN XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER XOAUTH
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-ENHANCEDSTATUSCODES
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-PIPELINING
Net::SMTPS=GLOB(0x2b41ae0)<<< 250-CHUNKING
Net::SMTPS=GLOB(0x2b41ae0)<<< 250 SMTPUTF8
Net::SMTPS=GLOB(0x2b41ae0)>>> AUTH LOGIN
Net::SMTPS=GLOB(0x2b41ae0)<<< 334 VXNlcm5hbWU6
Net::SMTPS=GLOB(0x2b41ae0)>>> c21hcnQ4MTZwaWthQGdtYWlsLmNvbQ==
Net::SMTPS=GLOB(0x2b41ae0)<<< 334 UGFzc3dvcmQ6
Net::SMTPS=GLOB(0x2b41ae0)>>> 
Net::SMTPS=GLOB(0x2b41ae0)<<< 535-5.7.8 Username and Password not accepted. Learn more at
Net::SMTPS=GLOB(0x2b41ae0)<<< 535 5.7.8  https://support.google.com/mail/answer/14257 i69sm1748185pfk.30 - gsmtp

無料ssl証明書のLet's Encryptのnginx on amazon linux へのお試し導入

ググルと、「Let's Encryptは、amazon linuxでは試験段階」と言う情報が チラホラ見られましたが、私の試した範囲では、迷うようなことはありませんでした。

STEP0 参考url

何より日本語urlがあったお陰ですね。 https://letsencrypt.jp/docs/using.html#installation

STEP1 クライアントのinstall

# cd /usr/local
git clone https://github.com/certbot/certbot

STEP2 証明書のinstall

# /usr/local/certbot/certbot-auto certonly --debug --webroot \
>   -d hoge.example.mydns.jp \
>   --webroot-path /usr/share/nginx/html
Version: 1.1-20080819
Version: 1.1-20080819

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at
   /etc/letsencrypt/live/hoge.example.mydns.jp/fullchain.pem. Your
   cert will expire on 2016-10-05. To obtain a new or tweaked version
   of this certificate in the future, simply run certbot-auto again.
   To non-interactively renew *all* of your certificates, run
   "certbot-auto renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le


# ls -l /etc/letsencrypt/live/hoge.example.mydns.jp
  cert.pem -> ../../archive/hoge.example.mydns.jp/cert1.pem
  chain.pem -> ../../archive/hoge.example.mydns.jp/chain1.pem
  fullchain.pem -> ../../archive/hoge.example.mydns.jp/fullchain1.pem
  privkey.pem -> ../../archive/hoge.example.mydns.jp/privkey1.pem

STEP3 nginxの設定

# vi /etc/nginx/nginx.conf
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;
    index   index.html index.htm;

    server {
        listen       80;
    return 302 https://$host$request_uri;
    }



  server {
    listen 443 ssl;
 
    ssl_certificate /etc/letsencrypt/live/hoge.example.mydns.jp/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/hoge.example.mydns.jp/privkey.pem;
 
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout 5m;
 
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
 
    root /usr/share/nginx/html;
 
    index index.html index.htm index.nginx-debian.html;
 
    server_name _;
 
    location / {
      # First attempt to serve request as file, then
      # as directory, then fall back to displaying a 404.
      try_files $uri $uri/ =404;
    }
  }
}

STEP4 nginxの再起動

# /etc/rc.d/init.d/nginx restart

その他

Let's Encrypt によるssl証明書の有効期間は90日間らしく 「certbot renew」コマンドで証明書を更新するようです。

気が向いたら、証明書を更新します。

perlで mysqlのauto_incrementの値を確認するには、mysql_insertid

sub add_auto_increment_record {
    my ($self,$dbh) = @_;

    my $sql =<<EOF;
insert into test_table (key, val) values (?, ?)
EOF
    my $sth = $dbh->prepare($sql);
    my @vals = ('FOO','BAA');
    unless($sth->execute(@vals)){
        $self->error( $sth->errstr );
        return undef;
    }
    return $sth->{mysql_insertid};
}

ITILにおけるインシデント管理と、問題管理

そもそも、両者は目的が異なります

項目 内容
インシデント管理 迅速に、通常のサービス運用(SLA範囲)を回復
問題管理 インシデントの根本原因の検知と解決、予防

インシデント・ライフサイクルと、1次,2次...サポート

以下の通り (ITIL本からの抜粋です) f:id:end0tknr:20160629085345p:plain

jQuery UI Datepickerに対し、日本語化、複数月表示、祝日,土日色付け

普段、bootstrapを使用する機会が多い為、 カレンダー入力はそのplug-inである bootstrap-datepicker.js を使用していましたが...

end0tknr.hateblo.jp

bootstrapはバージョンアップが早い為でしょうか、 手元にあるbootstrapを最新版に更新した所、bootstrap-datepicker.js が動作しなくなりました。

いい機会かも知れませんので、 jQuery UI Datepickerに、日本語化、複数月表示、祝日,土日色付け を対応させる方法を調べてみました。

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script src="jquery.js"></script>
<!-- http://jqueryui.com/ よりダウンロード -->
<link rel="stylesheet" href="jquery-ui/jquery-ui.css">
<script src="jquery-ui/jquery-ui.js"></script>
<!-- https://github.com/jquery/jquery-ui/tree/master/ui/i18n で日本語化 -->
<script src="jquery-ui/jquery-datepicker-ja.js"></script>

<!-- http://www.h3.dion.ne.jp/~sakatsu/ -->
<!-- http://www.ka-net.org/blog/?p=2158 で、祝日,土,日を色付け-->
<script src="HolidayChk.js"></script>
<script>
$(function() {
   $("#datepicker").datepicker({
     dateFormat:'yy-mm-dd',//日付の書式を変更
     numberOfMonths: 3,    //複数月を表示
     //複数月表示の場合、画面に入らないこともある為、draggableに
     beforeShow: function(){ $("#ui-datepicker-div").draggable(); },
     // HolidayChk.js 祝日,土日を色付け
     beforeShowDay: function(date) { //
       var dateStr =
    [date.getFullYear(),date.getMonth()+1,date.getDate()].join('-');
       var holidayName = ktHolidayName(dateStr);
       if(holidayName)        return [true, "date-holiday"];
       if(date.getDay() == 0) return [true, "date-holiday"];
       if(date.getDay() == 6) return [true, "date-saturday"];
       return  [true];
     },
     showAnim: '' //NONE
   });

});
</script>

<style>
.date-holiday  .ui-state-default { background-color:#FF9999; }
.date-saturday .ui-state-default { background-color:#66CCFF; }
</style>  
</head>
<body>
 
日付 <input type="text" id="datepicker">
 
</body>
</html>

↑こう書くと、↓こう表示されます f:id:end0tknr:20160626102753p:plain ※カレンダー部分は、ドラッグもできます

参考にさせて頂いたurl

「参考」と言うより、そのままなんですけどね。

jQuery UI

jqueryui.com

カレンダーの日本語化

https://github.com/jquery/jquery-ui/tree/master/ui/i18ngithub.com

カレンダーに祝日,土,日を色付け

http://www.h3.dion.ne.jp/~sakatsu/ www.ka-net.org

nginx + amon2 for perl でのbasic認証

nginx設定

「proxy_set_header X-Forwarded-User $remote_user;」を設定します

#user  nobody;
worker_processes  1;

error_log  logs/error.log;
#error_log  logs/error.log  notice;

#pid        logs/nginx.pid;

events {
    worker_connections  1024;
}

http {
    server {
        listen       8080;
        server_name  localhost;

        location / {
            proxy_pass      http://127.0.0.1:5000;

            auth_basic "MEMBER ONLY";
            auth_basic_user_file /home/endo/dev/htpasswd;

            proxy_set_header Host             $host;
            proxy_set_header X-Real-IP        $remote_addr;
            proxy_set_header X-Forwarded-For  $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-User $remote_user; ## HERE !!
        }
    }
}


amon2 というか、perl アプリケーション

contextオブジェクトから、「HTTP_X_FORWARDED_USER」を取り出します

sub get_login_user {
    my ($self,$c) = @_;
    my $user_id = $c->req->{env}->{HTTP_X_FORWARDED_USER};
    return Splats::Model::User->new($c,$user_id);
}

perl で db tableのカラム定義をcasual & dynamic に確認

したい場合、 DBI で、 desc ~ や、 show create table ~ くらいしかないの?

#!/usr/local/bin/perl
use strict;
use utf8;
use DBI;
use Data::Dumper;

my $DB_CONF =
    {host=>'localhost',
     port=> 3306,
     db_name=> 'ないしょ',
     db_user=> 'ないしょ',
     db_pass=> '',
     db_opt=>
     {AutoCommit=> 0,
      PrintError=> 0,
      RaiseError=> 1,
      ShowErrorStatement=>  1,
      AutoInactiveDestroy=> 1,
      mysql_enable_utf8=> 1,
      mysql_auto_reconnect=> 0},
     client_encoding=> 'utf8'
    };



main(@ARGV);

sub main {

    my $dbh = connect_db($DB_CONF);

    my $tbl_name = 'h_juchuu';

    print_desc_tbl($dbh, $tbl_name);

    print_show_create_tbl($dbh, $tbl_name);

    $dbh->disconnect();
}


sub print_show_create_tbl {
    my ($dbh, $tbl_name) = @_;

    my $sql = "show create table $tbl_name";
    my $sth = $dbh->prepare($sql);
    unless( $sth->execute() ){
        die $sth->errstr;
    }

    while( my $row = $sth->fetchrow_hashref){
        print $row->{'Create Table'},"\n";
    }
}


sub print_desc_tbl {
    my ($dbh, $tbl_name) = @_;

    my $sql = "desc $tbl_name";
    my $sth = $dbh->prepare($sql);
    unless( $sth->execute() ){
        die $sth->errstr;
    }

    while( my $row = $sth->fetchrow_hashref){
        print join("\t",$row->{Field},$row->{Key},$row->{Type},),"\n";
    }
}


sub connect_db {
    my ($db_conf) = @_;

    my $dbh
        = DBI->connect(
        "DBI:mysql:database=$db_conf->{db_name};host=$db_conf->{host}",
        $db_conf->{db_user}, $db_conf->{db_pass}, $db_conf->{db_opt} );
    $dbh->do("SET NAMES $db_conf->{client_encoding}")
        or die "cannot set encoding";
    return $dbh;
}

1;
__END__

OpenJDKのyum install と alternatives による java切替え

参考url : http://openjdk.java.net/install/

$ su -
# yum install java-1.8.0-openjdk
    :
# which java
/usr/bin/java
[endo@cent6 java]$ java -version
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)

# alternatives --config java

There are 3 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
   1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
   2           /usr/lib/jvm/jre-1.6.0-openjdk.x86_64/bin/java
*+ 3           /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java

Enter to keep the current selection[+], or type selection number:

どうやら「alternatives --install」は、yum ?が行っているみたい。

# alternatives --install /usr/bin/java java /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java 2

またJAVA_HOMEは次のようにしておけば、よい気がします

export JAVA_HOME='/usr/lib/jvm/java'

ImageMagick と PerlMagick をまとめてinstall - 再び

end0tknr.hateblo.jp

以前も同様のエントリを書いていますが、ImageMagick と PerlMagick をまとめてinstall であれば、 configure の 「--with-perl=/usr/local/bin/perl」オプションを使用しましょう

$ wget http://www.imagemagick.org/download/ImageMagick.tar.gz
$ tar -zxvf ImageMagick.tar.gz
$ cd ImageMagick-7.0.1-10
$ ./configure --help
$ ./configure --with-perl=/usr/local/bin/perl
$ make
$ make check
$ su
# make install

特定のアプリ専用にinstallする場合は以下

$ sudo su -
# su - eanapache
$ cd /myapp/local

$ export CPPFLAGS="-I/myapp/local/zlib-1.2.8/include -I/myapp/local/libpng-1.6.13/include -I/myapp/local/jpeg-9a/include"
$ export LDFLAGS="-L/myapp/local/zlib-1.2.8/lib -L/myapp/local/libpng-1.6.13/lib -L/myapp/local/jpeg-9a/lib -L/myapp/local/ImageMagick-7.0.2-0/lib -Wl,-rpath,/myapp/local/ImageMagick-7.0.2-0/lib"
$ export LD_LIBRARY_PATH="/myapp/local/ImageMagick-7.0.2-0/lib"


$ wget http://www.imagemagick.org/download/ImageMagick.tar.gz
$ tar -zxvf ImageMagick.tar.gz
$ cd ImageMagick-7.0.2-0
$ ./configure --help

$ ./configure \
  --prefix=/myapp/local/ImageMagick-7.0.2-0 \
  --with-perl=/myapp/local/perl5/bin/perl

$ make
$ make check


## PerlMagick(Image::Magick)の更新日時をチェック

$ find /myapp/local/perl5 -name Magick.pm -exec ls -lh {} \;
-r--r--r-- 1 eanapache eanapache 1.9K Jun 13 11:16 /myapp/local/perl5/lib/site_perl/5.18.4/x86_64-linux/Image/Magick.pm

shc で、shell scriptをバイナリ化

すっかり、shcの名前を忘れていたのでメモ

install

といっても、makeだけ

$ wget http://www.datsi.fi.upm.es/~frosal/sources/shc-3.8.9b.tgz
$ tar -zxvf shc-3.8.9b.tgz
$ cd shc-3.8.9b
$ make
$ ls -l shc
-rwxrwxr-x 1 endo endo 36097 Jun  2 22:02 shc

usage

といっても、shcに -f でshellを渡すだけ

$ shc-3.8.9b/shc -f test.sh
$ ls -l test.sh*
-rw-r--r-- 1 endo endo    33 Jun  2 22:03 test.sh
-rwx-wx--x 1 endo endo 11648 Jun  2 22:03 test.sh.x
-rw-rw-r-- 1 endo endo  9464 Jun  2 22:03 test.sh.x.c
$ ./test.sh.x

Unicodeプロパティによる文字種の判別

developer.hatenastaff.com ↑こちらを読んで、↓こちらを思い出した。 end0tknr.hateblo.jp

unicode.org のお陰で、文字種の判別は随分、楽になりましたが

  • 「①」「㈱」等のいわゆる機種依存文字の判別が自分の認識と異なる。
  • 「A」「A」等の全角英数字の判別が自分の認識と異なる。
  • 「斎藤」「斉藤」「齋藤」を簡単に同一視したい。

で、モヤモヤが解消しきれていない。地道に行くしかないんですかねぇ

参考url

なんとなく、確認用のscriptを書いてみたけど...

特に意味はありません。ただの写経です

#!/usr/local/bin/perl
use strict;
use utf8;
use Encode;

# http://perldoc.jp/docs/perl/5.10.0/perlunicode.pod#Unicode32Character32Properties
# http://developer.hatenastaff.com/entry/2016/05/31/123457
# http://js-next.hatenablog.com/entry/2016/04/21/013010
# http://unicode.org/Public/UNIDATA/ScriptExtensions.txt
main();

sub main {

#    chk_General_Category();
#    chk_Script();
    chk_Script_Extensions();
#    chk_East_Asian_Width();

}

sub chk_General_Category { # 一般カテゴリ

    my $uc_prop_type = 'General_Category';  #

    for my $char ( qw/A A a a あ ア ア/ ){
        my @uc_prop_vals =
            ('Letter',          #表音文字・表語文字
             'UppercaseLetter', #大文字
             'OtherLetter');    #他の文字
        for my $uc_prop_val ( @uc_prop_vals ){
            chk_unicode_prop($uc_prop_type, $uc_prop_val,$char);
        }
    }

    for my $char ( qw/1 1 ① 一 , . ,/ ){
        my @uc_prop_vals =
            ('Number',
             'DecimalNumber',
             'LetterNumber',
             'OtherNumber');
        for my $uc_prop_val ( @uc_prop_vals ){
            chk_unicode_prop($uc_prop_type, $uc_prop_val,$char);
        }
    }
}

# http://www.unicode.org/Public/UNIDATA/Scripts.txt
sub chk_Script { #

    my $uc_prop_type = 'Script';

    for my $char ( qw/亜 あ ア ア 一 ー α/ ){
        my @uc_prop_vals =
            ('Katakana',
             'Han',
             'Common');
        for my $uc_prop_val ( @uc_prop_vals ){
            chk_unicode_prop($uc_prop_type, $uc_prop_val,$char);
        }
    }
}

sub chk_Script_Extensions { #

    my $uc_prop_type = 'Script_Extensions';

    for my $char ( qw/亜 あ ア ア 一 ー α ㈱/ ){
        my @uc_prop_vals =
            ('Hiragana',
             'Katakana',
             'Han',
             'Common');
        for my $uc_prop_val ( @uc_prop_vals ){
            chk_unicode_prop($uc_prop_type, $uc_prop_val,$char);
        }
    }
}

sub chk_East_Asian_Width { #

    my $uc_prop_type = 'East_Asian_Width';

    for my $char ( qw/あ ア ア ㈱ ① 1 1/ ){
        my @uc_prop_vals =
            ('Wide',
             'Narrow',
             'Ambiguous',
            );
        for my $uc_prop_val ( @uc_prop_vals ){
            chk_unicode_prop($uc_prop_type, $uc_prop_val,$char);
        }
    }
}



sub chk_unicode_prop {
    my ($uc_prop_type,$uc_prop_val, $char) = @_;

    my $uc_prop_type_val = join('=',$uc_prop_type, $uc_prop_val);
    if( $char =~ m/\p{$uc_prop_type_val}/){
        print encode('utf8',
                     "'$char' = $uc_prop_type_val .\n");
        return;
    }
    print encode('utf8',
                 "'$char' ≠ $uc_prop_type_val .\n");
}

1;

「openssl s_client」で暗号方法の対応状況を調べる

$ openssl s_client -connect www.google.co.jp:443 -cipher AES256-SHA
$ openssl s_client -connect www.google.co.jp:443 -cipher DHE-RSA-AES128-SHA

上記の実行で、たくさんの文字列が表示されれば、対応済。そうでなければ、未対応。

Module::Load for perl で installされた module の有無をまとめて確認

#!/usr/local/bin/perl
use strict;
use Module::Load;

main();

sub main {

    my @load_classes = qw/Apache::DBI  Apache2::Reload Archive::Tar
        Archive::Zip Crypt::Eksblowfish::Bcrypt      Crypt::SSLeay
        Date::Format DBI     DBD::mysql              DBD::ODBC
        DBD::Oracle  DBD::Pg Encode::HanExtra        IO::Socket::SSL
        JSON::XS     List::Util::XS  LWP::UserAgent  Mail::IMAPClient
        IO::Socket::SSL      ModPerl::Util           Net::DNS
        Net::LDAP    Template        Template::Stash::XS
        Text::CSV_XS Time::HiRes     Time::Piece     XML::LibXML
        XML::LibXSLT XML::Parser     YAML::XS/;

    for my $load_class (@load_classes) {
        eval { Module::Load::load $load_class };
        if ($@) {
            print STDERR "NOT INSTALLED $load_class \n";
        }
    }

}

1;

↑こう書くと、↓こう表示されます

$ ./chk_cpan_modules.pl
NOT INSTALLED DBD::Oracle 
NOT INSTALLED DBD::Pg 

Module::Pluggable でも同様のことができるかもしれないので、以前のurlを貼っておきます end0tknr.hateblo.jp