無精・短気・傲慢

perlの事 いろいろ

春分の日・秋分の日

春分の日・秋分の日は前年に決まる

春分の日」及び「秋分の日」については、国立天文台が、毎年2月に翌年の「春分の日」、「秋分の日」を官報で公表しています。

  春分の日・秋分の日を求める

公転時の誤差によって日にちの確定ができない春分の日ですが、何年後・何十年後の遠い将来まで予測することはできるのでしょうか。

地球の運行状態などが今のまま続くと仮定した場合、将来の春分日や秋分日も、計算で予測することが可能です。

 計算

1980年を基準に1980年から2099年までの春分の日・秋分の日を計算する

#------------------------------------------------------------------
sub get_equinox_day{
#------------------------------------------------------------------

=head2 春分の日秋分の日を求める [get_equinox_day] 

=over 2

指定した年の春分日・秋分日をもとめる
(1980年から2099年に適用)
($vernal,$autumnal)=get_equinox_day($y);

=back

=cut

   my $s = shift;
   my ($yy)=@_;
   my ($vernal) = int(20.8431+0.242194*($yy-1980)-int(($yy-1980)/4));
   my ($autumnal)=int(23.2488+0.242194*($yy-1980)-int(($yy-1980)/4));

   return ($vernal,$autumnal);
}

 

閉じれる半透明のパネル

 半透明のパネルを追加

[html]

<div id="overlay" class="content">
    <div class="inner">
    @{[$s->panel_content()]}
            <div id="panel" class="panel hide"></div>
    </div>
</div>

[css]

.content{
  position:absolute;
  top: 375px;
  left:0px;
  width:60%;
  min-width:315px;
  display:none;
  z-index:100;
}
.inner{
  padding:10px;
  background-color:rgba(0,0,0,0.5);
}

 閉じたり開いたり

[JavaScript]

<script type="text/javascript">
    $(function() {
        $('#panel').toggle(
            function() {
                $(this).addClass('show').removeClass('hide');
                $('#overlay').stop().animate( { left : - $('#overlay').width()   + 20 + 'px' }, 300 );
            },
            function() {
                $(this).addClass('hide').removeClass('show');
                $('#overlay').stop().animate( { left : '0px' }, 300 );
            }
        );
        $('#overlay').fadeIn(500);
    });

</script>

 作ってみる

 画面

 SOURCE

diff --git a/toolmmt/lib/Tool/mmt/Controller/Menu.pm b/toolmmt/lib/Tool/mmt/Controller/Menu.pm
index ef1ca1f..8ed6945 100644
--- a/toolmmt/lib/Tool/mmt/Controller/Menu.pm
+++ b/toolmmt/lib/Tool/mmt/Controller/Menu.pm
@@ -62,4 +62,48 @@
      }
      return $text;
  }
+ sub make_panel{
+     my $s = shift;
+     my $text = <<END_SCRIPT;
+<link rel="stylesheet" type="text/css" href="/css/demo.css" />
+
+<div id="overlay" class="content">
+    <div class="inner">
+    @{[$s->panel_content()]}
+            <div id="panel" class="panel hide"></div>
+    </div>
+</div>
+
+<script type="text/javascript">
+    \$(function() {
+        \$('#panel').toggle(
+            function() {
+                \$(this).addClass('show').removeClass('hide');
+                \$('#overlay').stop().animate( { left : - \$('#overlay').width() + 20 + 'px' }, 300 );
+            },
+            function() {
+                \$(this).addClass('hide').removeClass('show');
+                \$('#overlay').stop().animate( { left : '0px' }, 300 );
+            }
+        );
+        \$('#overlay').fadeIn(500);
+    });
+    window.onload = function(){
+//      document.getElementById("panel").click();
+    };
+
+</script>
+
+END_SCRIPT
+     return $text;
+ }
+ sub panel_content{
+     my $s = shift;
+     my $text = <<END_SCRIPT
+    <pre>
+    @{[`cal -3h`]}
+    @{[`date +"%a %b %d %Y"`]}
+    </pre>
+END_SCRIPT
+ }
  1;
diff --git a/toolmmt/public/css/demo.css b/toolmmt/public/css/demo.css
new file mode 100644
index 0000000..0941c15
--- /dev/null
+++ b/toolmmt/public/css/demo.css
@@ -0,0 +1,27 @@
+.content{
+  position:absolute;
+  top: 375px;
+  left:0px;
+  width:60%;
+  min-width:315px;
+  display:none;
+  z-index:100;
+}
+.inner{
+  padding:10px;
+  background:transparent url(/css/black.png) repeat top left;
+}
+.panel{
+  position:absolute;
+  height:86px;
+  width:20px;
+  right:0px;
+  top:10px;
+  cursor:pointer;
+}
+.hide{
+  background:transparent url(/css/hide.png) no-repeat center center;
+}
+.show{
+  background:transparent url(/css/show.png) no-repeat center center;
+}
diff --git a/toolmmt/templates/menu/menu.html.ep b/toolmmt/templates/menu/menu.html.ep
index ec27318..48724f8 100644
--- a/toolmmt/templates/menu/menu.html.ep
+++ b/toolmmt/templates/menu/menu.html.ep
@@ -1,5 +1,6 @@
 % layout 'default';
 % title 'menu' ;
+%== $self->make_panel();
 <table width=98%><tr><td style="vertical-align: top;">
 %   for my $r (@$_data){
 %       if ($r->{menukbn} =~ /^(H\d)/i){
                   

パスフレーズの入力内容を確認出来る様にする

   パスワードからパスフレーズ

あのパスワード規則、実は失敗作だった数字・記号・大文字の組み合わせ、2003年に考案した人物が後悔しているらしい。

  • パスワードのルールは間違いだった
  • 「NISTスペシャルパブリケーション800-63」は今年2017年6月に全面改定
  • 「パスワード」ではなく、スペースも入れられる最低64文字の「英単語の組み合わせによるパスフレーズ」の使用を推奨
  • ユーザーがパスワードを変更すべきなのは、盗まれた兆候があった時だけ

    ログイン画面

なが~いパスフレーズ(漢字を含む)を入力できる様にすると入力内容を確認したくなるのでパスフレーズを確認出来る様にした。

チェックボックスのクリックでパスワードの表示を切り替えるサンプル画面

Index: templates/auth/login.html.ep
===================================================================
--- templates/auth/login.html.ep   (revision 145)
+++ templates/auth/login.html.ep   (working copy)
@@ -6,8 +6,21 @@
  <br>Name:
  %= text_field 'user',size => 60
  <br>password:
- %= text_field 'passwd',size => 60
+ %= text_field 'passwd',size => 60,id=>"passwd"
  <br>
+ <input type="checkbox" id="password-check" checked="checked">パスワードを表示する
+ <br>
  %= submit_button 'Login'
  %= hidden_field url => $url
 % end
+<script>
+ const pwd = document.getElementById('password');
+ const pwdCheck = document.getElementById('password-check');
+ pwdCheck.addEventListener('change', function() {
+     if(pwdCheck.checked) {
+         passwd.setAttribute('type', 'text');
+     } else {
+         passwd.setAttribute('type', 'password');
+     }
+ }, false);
+</script>
  • アンドロイドではpassword fieldでは日本語がいれられないのね、どうしよう・・・

セッションとユーザー紐づけ

 mojoliciusでセッションとユーザーを紐づけしてみた

LOGIN画面で認証したユーザーをセッションと紐づけてDBに登録しクッキーに保存したセッションにて以降の画面でユーザーを認識する。

  1. セッションが有効で無い時は認証画面を表示する。
  2. 認証画面での入力したユーザーとパスワードにてDBに登録したパスワードのハッシュ値と照合しパスワードの有効性を確認する。
  3. 入力値が有効の場合にセッションとユーザーを紐づけでDBに登録する。
  4. 元画面に戻る。
 

中置記法から抽象構文木(AST)変換し後置記法(逆ポーランド記法)の計算

 吉祥寺.pm #20 へ行ってきた

東京に出張に来ていたので2019/11/22吉祥寺.pm #20へ行ってきた。色々と刺激を受けた。発表のなかで、めもりー(@m3m0r7)さんの『PHP で AST 解析して Java の中間コードを生成する』に刺激を受けて、中置記法から抽象構文木(AST)変換し後置記法(逆ポーランド記法)の計算を作ってみた。以前に中置記法から後置記法(逆ポーランド記法)への変換と計算でスタックを使った逆ポーランド記法のプログラムを作ったが、今回はASTで計算してみた。(当然paerlで)

https://kabukawa.hatenablog.jp/entry/2019/11/25/012334 <-良くまとっ待っている

 Source

 実行

$ perl ast.pl 10+1
10 + 1
11
$

mojoliciousで動くように修正した。

 ast.pl

use lib 'lib';
use Ast;
use Data::Dumper;

my $c = Ast->new;
#my $t = $c->adjust('(100+2**3-((1+2)/(4+-2))*(-10))');
my $t = $c->adjust(join '',@ARGV);
$c->item_split($t);
my $root = $c->makeTree(@{$c->{item}});

print "$t\n";
print $c->readTree($root),"\n";;

 Ast.pm

package Ast;
use strict;
use warnings;
use Data::Dumper;

my $op = +{ '-' => [sub {$_[0] - $_[1]},1],         # オペレータ定義
           '+' => [sub {$_[0] + $_[1]},1],
           '*' => [sub {$_[0] * $_[1]},2],
           '/' => [sub {$_[0] / $_[1]},2],
           '%' => [sub {$_[0] % $_[1]},2],
           '**' => [sub {$_[0] ** $_[1]},3],
           #'x' => [sub {$_[0] * $_[1]},8], # 多項式対応?
           '(' => [sub { },9],
           ')' => [sub { },10],
        };
sub ast{
    Ast->new('formula'=>shift())->{anser};
}
sub _ast{
    my $s = shift;
    $s->{anser} = $s->readTree($s->makeTree(@{$s->item_split($s->adjust(shift))->{item}}));
}
sub new {                                           # コンストラクター
    my $class = shift;
    my $self = {@_};
    bless $self,$class;
    $self->setReOps();
    $self->_ast($self->{formula}) if (exists $self->{formula});
    return $self;
}
sub setReOps{                                       # 演算子正規表現作成
    my $s = shift;
    $s->{ops} = join ('|',map {s/(.)/\\$1/g;$_;} sort {length $b <=> length $a} keys %$op);
    $s->{ops} = "(".$s->{ops}.")";
    return $s;
}
sub newNode{
    my $s = shift;
    return {data => shift(),left =>shift(),right=>shift()};
}
sub readTree{                                       # AST計算
    my ($s,$node) = @_;
    do{$node->{$_} = $s->readTree($node->{$_}) if(ref($node->{$_}) eq "HASH")} for ('left','right');
    exists $op->{$node->{data}} ? $op->{$node->{data}}->[0]($node->{left},$node->{right})
                                : $node->{data};
}
sub makeTree{                                       # ATS組み立て
    my $s = shift;
    while($_[0] eq '(' and $_[-1] eq ')'){
        my ($r,$sw) = (0,0);
        for(@_){                                    # '('の深さを計算
            $r++ if($_ eq '(');                     
            $r-- if($_ eq ')');
            $sw++ if($r == 1 and $_ eq '(');
        }
        if($sw == 1){                               #  一番外側の括弧を外す
            shift;
            pop;
        }else{
            last;
        }
    }
    return shift() if(@_ <= 1);                     # 要素が一つの時は要素を返す
    my ($prio,$i,$m,$r) = (99,-1,0,0);
    for(@_){                                        # 一番右側の一番プライオリティの低いオペレータを検索
        $i++;
        if(/^$s->{ops}$/){
            $r++ if($_ eq '(');
            $r-- if($_ eq ')');
            next if($r or $_ eq ')');              #  括弧の間は読み飛ばす
            if($op->{$_}->[1]+$r <= $prio){
                $prio = $op->{$_}->[1];
                $m = $i;
            }
        }
    }
    return $s->newNode($_[$m],                      # オペレータとオペランド(右と左)を返す
                            $s->makeTree(@_[0 .. $m-1]),
                            $s->makeTree(@_[$m+1 .. $#_])
                );
}
sub item_split{                                     # 計算式を要素に分解
    my $s = shift;
    my $text = shift || $s->{_text};
    $s->{item} = [split ' ',$text];
    return $s;
}
sub adjust{                                         # 計算式の要素をスペースで分割
    my ($s,$text) = @_;
    $text =~ s/$s->{ops}/ $1 /g;
    $text =~ s{([\d\)])\s*\(}{$1 \* \(}g;           #   開き括弧の前が演算子じゃない時に*を補完 ex). (1+2)(2-1) -> (1+2)*(2-1)
    $s->{_text} = $text =~ s/($s->{ops}\s*-)\s*/$1/g;
    return $text;
}
1;

--

 

mojoliciousでユーザー認証

 LOGIN画面を追加

 mmt.pm

Router認証処理を追加する。underで各処理の前に認証済みの確認処理を追加。認証を必要としない処理は元々のRouterを使う。

--- a/toolmmt/lib/Tool/mmt.pm
+++ b/toolmmt/lib/Tool/mmt.pm
@@ -16,15 +16,20 @@ sub startup {
   # Router
   my $r = $self->routes;
   $r->namespaces(['Tool::mmt::Controller']);
+  # ユーザー認証
+  my $sr = $r->under->to('auth#check');
   # Normal route to controller
   $r->get('/')->to('example#welcome');
-  $r->get('/mmt/:_table/desc')->to('mmt#desc');
-  $r->get('/mmt/:_table')->to(controller => $self->controller,action =>'mainform');
-  $r->post('/mmt/:_table')->to(controller => $self->controller,action => 'registry');
-  $r->get('/mmtx/:controller')->to(controller => $self->controller,action =>'mainform');
-  $r->post('/mmtx/:controller')->to(controller => $self->controller,action => 'registry');
-  $r->any('/mmtx/:controller')->to(controller => $self->controller,action => 'mainform');
-  $r->any('/rwt/:controller')->to(controller => $self->controller,action => 'print_main');
+  $sr->get('/logout')->to('auth#logout');
+  $sr->any('/login')->to('auth#login');
+  $sr->any('/mmt/login')->to('auth#login');
+  $sr->get('/mmt/:_table/desc')->to('mmt#desc');
+  $sr->get('/mmt/:_table')->to(controller => $self->controller,action =>'mainform');
+  $sr->post('/mmt/:_table')->to(controller => $self->controller,action => 'registry');
+  $sr->get('/mmtx/:controller')->to(controller => $self->controller,action =>'mainform');
+  $sr->post('/mmtx/:controller')->to(controller => $self->controller,action => 'registry');
+  $sr->any('/mmtx/:controller')->to(controller => $self->controller,action => 'mainform');
+  $sr->any('/rwt/:controller')->to(controller => $self->controller,action => 'print_main');
   $r->any('/api/:controller/:action')->to('example#welcom');
 }

 Auth.pm

認証処理は全てAuth.pmに押し込む。Routerのunderにて全ての処理の前にcheckを実行しsessionが確立していればreturn 1にて終了し、確立していない時はユーザー認証画面に繊維する。(ユーザー認証(userAuth)処理は未だ無い)

--- /dev/null
+++ b/toolmmt/lib/Tool/mmt/Controller/Auth.pm
@@ -0,0 +1,54 @@
+package Tool::mmt::Controller::Auth;
+use Mojo::Base 'Tool::mmt::Controller::Mmt';
+
+sub login {
+    my $s = shift;
+    $s->redirect_to($s->param('url')) if $s->param('url');
+    $s->render( template => 'mmt/index');
+}
+sub check {
+    my $s = shift;
+    # セッション確定済なら認証通貨
+    if($s->session('session')){
+        return 1;
+    }
+    #パスワードチェック
+    if($s->userAuth()){
+        return 1;
+    }
+    $s->stash( 'url' => $s->req->url->to_abs );
+    $s->render( template => 'auth/login');
+    return undef;
+}
+sub userAuth{
+    my $s = shift;
+    my $user = $s->param('user')||'';
+    my $pass = $s->param('passwd')||'';
+    if ($user eq '' or $pass eq '' or $user =~ /(admin|root)/i){
+        $s->param('user','guest');
+        $s->param('passwd','guest01');
+        return undef;
+    }
+    my $sessionId = $s->randomStr();
+    $s->session('session' => $sessionId);
+    return 1;
+}
+sub logout{
+    my $s = shift;
+    # セッション削除
+    $s->session(expires => 1);
+    $s->stash( 'url' => 'login' );
+    $s->render( template => 'auth/login');
+}
+sub randomStr{
+    my $s = shift;
+    my %arg = (-length =>16,
+                        -str => (join '',('A'..'Z','a'..'z','0'..'9')),
+                         @_);
+    my @str = split //,$arg{'-str'};
+    my $str = "";
+    for(1 .. $arg{'-length'}){$str .= $str[int rand($#str+1)];}
+    return $str;
+}
+
+1;

 auth/login.html.ep

ログイン画面

--- /dev/null
+++ b/toolmmt/templates/auth/login.html.ep
@@ -0,0 +1,13 @@
+% layout 'defrwt';
+% title 'login' ;
+<h2>Login</h2>
+
+%= form_for login => (method => 'post') => begin
+ <br>Name:
+ %= text_field 'user'
+ <br>password:
+ %= text_field 'passwd'
+ <br>
+ %= submit_button 'Login'
+ %= hidden_field url => $url
+% end

 default.html.ep

デフォルト画面にlogoutのリンクを追加

--- a/toolmmt/templates/layouts/default.html.ep
+++ b/toolmmt/templates/layouts/default.html.ep
@@ -50,6 +50,7 @@
   <body>
     <input type=hidden name=_focus id=_focus value=<%= param('_focus') %>>
     <div class="main">
+      <a href=/logout>logout</a>
       <%= content %>
     </div>
     <div class="sidebar">

 mmt/index.html.ep

ログイン後のスタートページ

--- /dev/null
+++ b/toolmmt/templates/mmt/index.html.ep
@@ -0,0 +1,3 @@
+% layout 'default';
+% title "mmt - index " ;
+<h1>INDEX</h1>