convert excel cell coordinate “a1 notation”/”r1c1 notation” by Excel::Writer::XLSX::Utility for perl

Standard

http://search.cpan.org/perldoc?Excel%3A%3AWriter%3A%3AXLSX

#!/usr/local/bin/perl
use strict;
use warnings;
use utf8;
# use Math::BaseCalc;
use Excel::Writer::XLSX::Utility;
use Data::Dumper;

main();

sub main {

my $co_a1_org = "C2";
my ( $row, $col ) = xl_cell_to_rowcol( $co_a1_org );
print "$co_a1_org -> ($row, $col)\n";

my @co_r1c1_org = (2,30);
my $co_a1 = xl_rowcol_to_cell( @co_r1c1_org );
print "($co_r1c1_org[0], $co_r1c1_org[1]) -> $co_a1\n";
}
$ ./foo.pl
C2 -> (1, 2)
(2, 30) -> AE3

logging at client (javascript), and send log to server.

Standard
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
  <button type="button" 	  onClick="log.error('LOG1','LOG2' );">TEST ERROR</button>
  <button type="button" 	  onClick="log.warn('LOG1','LOG2' );">TEST WARN</button>
  <button type="button" 	  onClick="log.info('LOG1','LOG2' );">TEST INFO</button>
  <button type="button" 	  onClick="log.debug('LOG1','LOG2' );">TEST DEBUG</button>
</body>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/Logger.js"></script>
<script>
 $(document).ready(function(){
//   log.set_level('none'); // if you need ...
 });
</script>
</html>

(function() {
    var Logger = function(){
        this.level = this.LEVEL['info']; // set default disp level
    };

    Logger.prototype = {
        LEVEL : {none:0, error:1, warn:2, info:3, debug:4 },
        SERVER_LOG_URL : '/client_log.png', //if you need , set url

        set_level: function(lavel){
            this.level = this.LEVEL[lavel];
        },
        error : function(){
            this._log(arguments.callee.name,this._args2array(arguments));
        },
        warn : function(){
            this._log(arguments.callee.name,this._args2array(arguments));
        },
        info : function(){
            this._log(arguments.callee.name,this._args2array(arguments));
        },
        debug : function(){
            this._log(arguments.callee.name,this._args2array(arguments));
        },

        _is_disp: function( level ){ //check console object and log level.
            if(window.console &&
               typeof window.console[level] === 'function' &&
               this.level >= this.LEVEL[level] ){
                return true;
            }
            return false;
        },
        _log: function(func_name, msgs){
            if(! this._is_disp(func_name)) return;
            console[func_name]( msgs.join(' '));

            if(this.SERVER_LOG_URL ){
                this._log_to_server(func_name, msgs);
                return;
            }
        },
        _log_to_server: function(func_name, msgs){
            var msgs_str = func_name +'='+ msgs.join('_');
            var now  = (new Date()).getTime() + Math.random() * 1000 ;
            var url =
                this.SERVER_LOG_URL +'?'+ encodeURI(msgs_str) +"&time="+now;
            var dummy_img = new Image();
            dummy_img.src = url;
        },

        _args2array : function(arguments){ // for variable arguments size
            var ret = [];
            for (var i = 0; i < arguments.length; i++) {
                ret.push(arguments[i]);
            }
            return ret;
        }

    };
    window.log = new Logger();
})();

download NHK RADIO GOGAKU LESSON streaming file by rtmpdump

Standard
#!/usr/local/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
use FindBin;
use LWP::UserAgent;
use XML::Simple;
use Data::Dumper;

## NHKゴガク https://www2.nhk.or.jp/gogaku/english/

my $MUSIC_OUT_DIR = $FindBin::Bin;

my $MUSIC_LIST_ROOT = 'https://www2.nhk.or.jp/gogaku/st/xml';
my $MUSIC_LIST_CHANNELS =
    {english=&gt;[
               'enjoy',         #エンジョイ・シンプル・イングリッシュ
               'basic1',        #基礎英語1
               'basic2',        #基礎英語2
               'basic3',        #基礎英語3
               'kaiwa',         #ラジオ英会話
               'timetrial',     #英会話タイムトライアル
               'kouryaku',      #攻略!英語リスニング
               'business1',     #入門ビジネス英語
               'business2',     #実践ビジネス英語
              ],
    };

# There are some paramaters
# in https://www2.nhk.or.jp/gogaku/st/flash/sound/ggk_str_pc3.swf , below.
# You can extract from swf file
#  by Flare ( http://www.nowrap.de/flare.html ).
my $MUSIC_FILE_ROOT = 'rtmpe://flvs.nhk.or.jp:1935/ondemand';
my $MUSCI_FILE_SUB_PATH = 'mp4:flv/gogaku-stream/mp4';

my $RTMPDUMP_CMD = '/usr/local/bin/rtmpdump';
my $FFMPEG_CMD = '/usr/bin/ffmpeg';

main(@ARGV);

sub main {
    my (@cmd_args) = @_;

    for my $lang (sort keys %$MUSIC_LIST_CHANNELS ){
        for my $channel (@{$MUSIC_LIST_CHANNELS-&gt;{$lang}}){
            ## DOWNLOAD CHANNEL INFOS
            my $channel_infos = get_music_list($lang,$channel);

            next if(ref($channel_infos) ne 'ARRAY' or
                    scalar(@$channel_infos) ==0 );

            my $out_dir = get_output_dir($lang,$channel);

            for my $channel_info ( @$channel_infos ){
                ## DOWNLOAD MUSIC FILE by rtmpdump
                my $music_file = get_music_file($channel_info, $out_dir);
                next unless $music_file;

                ## CORRECT by ffmpeg
                my $mp4_file = conv_to_mp4($music_file);
                print Encode::encode('utf8',&quot;DONE $mp4_file&quot;),&quot;\n&quot;;

                unlink $music_file or die &quot;$music_file$!&quot;;
            }
        }
    }
}

sub conv_to_mp4 {
    my($org_file) = @_;

    my $new_file = &quot;$org_file.mp4&quot;;
    my $cmd = &quot;$FFMPEG_CMD -loglevel error -y -i $org_file $new_file&quot;;

    my $fh;
    unless( open $fh, '-|', $cmd ){
        print STDERR Encode::encode('utf8',&quot;fail open $cmd&quot;),&quot;\n&quot;;
        return;
    }
    unless( close($fh) ){
        print STDERR Encode::encode('utf8',&quot;fail close $cmd&quot;),&quot;\n&quot;;
        return;
    }

    return $new_file;
}

sub get_output_dir {
    my($lang,$channel) = @_;

    my $out_dir_0 = join('/',$MUSIC_OUT_DIR,$lang);
    if(not -d $out_dir_0){
        mkdir $out_dir_0 or die &quot;fail mkdir $out_dir_0 $!&quot;;
    }
    return $out_dir_0;

    # my $out_dir = join('/',$MUSIC_OUT_DIR,$lang,$channel);
    # if(not -d $out_dir ){
    #     mkdir $out_dir or die &quot;fail mkdir $out_dir $!&quot;;
    # }
    # return $out_dir;
}

sub get_music_file {
    my ($channel_info, $out_dir) = @_;

    my $url = join('/',
                   $MUSIC_FILE_ROOT,
                   $MUSCI_FILE_SUB_PATH,
                   $channel_info-&gt;{file});
    my $out_file = join('/',
                        $out_dir,
                        &quot;$channel_info-&gt;{title}_$channel_info-&gt;{hdate}&quot;);
    my $cmd = &quot;$RTMPDUMP_CMD --quiet -r $url -o $out_file&quot;;
    my $fh;
    unless( open $fh, '-|', $cmd ){
        print STDERR Encode::encode('utf8',&quot;fail open $cmd&quot;),&quot;\n&quot;;
        return;
    }
    unless( close($fh) ){
        print STDERR Encode::encode('utf8',&quot;fail close $cmd&quot;),&quot;\n&quot;;
        return;
    }

    return $out_file;
}

sub get_music_list {
    my ($lang, $channel) = @_;

    my $url = join('/',$MUSIC_LIST_ROOT,$lang, $channel,'listdataflv.xml');
    my $ua = LWP::UserAgent-&gt;new;
    my $res = $ua-&gt;get($url);
    if(not $res-&gt;is_success ) {
        print STDERR $res-&gt;status_line , &quot; $url\n&quot;;
        return [];
    }

    my $xml_content = $res-&gt;content;
    $xml_content = Encode::decode('utf8',$xml_content);
    my $ret = XML::Simple::XMLin($xml_content);

    return $ret-&gt;{music};
}

install apache2.2 + perl5.18 + mod_perl2.0.9

Standard

install perl 5.18

$ wget http://www.cpan.org/src/5.0/perl-5.18.4.tar.gz
$ tar -xvf perl-5.18.4.tar.gz
$ cd perl-5.18.4
$ ./Configure -Dusethreads -Accflags="-fPIC" -de
$ make
$ make test
$ su
# make install

※「-Dusethreads -Accflags=”-fPIC”」option are needed by mod_perl.

install apache2.2

$ wget http://ftp.riken.jp/net/apache//httpd/httpd-2.2.31.tar.gz
$ tar -xvf httpd-2.2.31.tar.gz
$ cd httpd-2.2.31
$ ./configure --prefix=/home/endo/local/apache22 \
              --with-mpm=prefork \
              --enable-proxy \
              --enable-modules=all \
              --enable-so
$ make
$ make install

install mod_perl

$ wget http://www.apache.org/dyn/closer.cgi/perl/mod_perl-2.0.9.tar.gz
$ tar -xvf mod_perl-2.0.9.tar.gz
$ cd mod_perl-2.0.9
$ /usr/local/bin/perl Makefile.PL \
          USE_APXS=1 \
          WITH_APXS=/home/endo/local/apache22/bin/apxs \
          EVERYTHING=1
$ make
$ make test
$ su
# make install

edit httpd.conf & startup.pl

$ vi /home/endo/local/apache22/conf/httpd.conf
  :
LoadModule perl_module modules/mod_perl.so
PerlRequire /home/endo/local/apache22/conf/startup.pl

PerlSetEnv XING_CONF     /home/endo/dev/xing/etc/config.yaml

<Directory "/home/endo/dev/xing/app">
    AllowOverride All
    Order allow,deny
    Allow from all

    AuthType BASIC
    AuthUserFile /home/endo/dev/htpasswd
    AuthName "COLINUX MEMBERS"
    require valid-user

    <Files "*.pl">
       Options ExecCGI
       AddHandler cgi-script .pl
       SetHandler perl-script
       PerlHandler ModPerl::Registry
       PerlSendHeader On
    </Files>
</Directory>
Alias /Xing /home/endo/dev/xing/app
$ vi /home/endo/local/apache22/conf/startup.pl
  :
#/usr/local/bin/perl

BEGIN {
    use lib qw(.
               /home/endo/dev/xing/lib
             );
}

use NMW::Template;
$NMW::Template::ENCODING = 'utf8';
@NMW::Template::template_path=('/home/endo/dev/xing/tmpl');

use CGI;
$CGI::LIST_CONTEXT_WARN = 0;

#use Devel::Cover;
#$DEVEL_COVER_OPTIONS='-dir,/home/endo/tmp';

1;

nginx + nginx-auth-ldap module

Standard

step1/3 – install

$ cd /home/endo/tmp

$ wget http://nginx.org/download/nginx-1.9.3.tar.gz
$ tar -xvf nginx-1.9.3.tar.gz

$ wget https://www.openssl.org/source/openssl-1.0.2d.tar.gz
$ tar -xvf openssl-1.0.2d.tar.gz

$ git clone https://github.com/kvspb/nginx-auth-ldap.git

$ cd nginx-1.9.3
$ ./configure --prefix=/home/endo/local/nginx \
              --with-http_ssl_module \
              --with-openssl=../openssl-1.0.2d \
              --add-module=../nginx-auth-ldap
$ make
$ make install

step2/3 – edit nginx.conf

$ vi /home/endo/local/nginx/conf/nginx_auth_ldap.conf

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    ldap_server ldap_sexy {
        url ldap://ldap.sexy.co.jp/ou=people,o=sexy-group?uid?sub?(objectClass=*)
        group_attribute uniqueMember;
        group_attribute_is_dn on;
        require valid_user;
    }

    server {
        listen       8080;
        server_name  localhost;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            auth_ldap "AUTH_LDAP";
            auth_ldap_servers ldap_sexy;
            root   html;
            index  index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

step 3/3 – start nginx

$ cd /home/endo/local/nginx
$ ./sbin/nginx -c conf/nginx_auth_ldap.conf

Re – UNIT TEST to Controller of Amon2 (for perl) by Test::More

Standard
use strict;
use warnings;
use utf8;
use HTTP::Cookies;
use JSON;
use Plack::Test;
use Plack::Util;
use Test::More;
use Test::Requires 'Test::WWW::Mechanize::PSGI';
use Data::Dumper;

$ENV{"PLACK_ENV"} = 'development';

my $cookie_jar = HTTP::Cookies->new(file => "./cookie.txt",
                                    autosave => 1,
                                    ignore_discard => 1);
$cookie_jar->set_cookie(undef,                  #version
                        "HTTP_mavi-id",         #key
                        'ushiro',               #val
                        "/",                    #pathu
                        "localhost.local");     #domain

my $app = Plack::Util::load_psgi 'script/ean-server';
my $mech = Test::WWW::Mechanize::PSGI->new(app => $app,
                                           cookie_jar=>$cookie_jar);

subtest 'sub_test_name_1'=> sub {
    $mech->get_ok("/");
    $mech->title_like(qr/トップ/s);
    $mech->content_like(qr/ean/s);
};

subtest 'sub_test_name_2'=> sub {
    $mech->get_ok("/report/group/settings");
    my $res_data = JSON::from_json( $mech->content );

    print STDERR Dumper($res_data);

};

done_testing;

UNIT TEST to Controller of Amon2 (for perl) by Test::More

Standard

You can unit test to controller of Amon2
If you make Amon2 plug-in “get_dummy_context()” as below,

use strict;
use utf8;
use t::Util;
use CGI;
use Date::Calc;
use JSON;
use Plack::Session;
use Plack::Test;
use Plack::Util;
use Test::More;
use Data::Dumper;

Ean-&gt;bootstrap;
use_ok('Ean::Controller::MemberEdit');
use_ok('Ean::ObjModel::Member');

my $SMART_ID = 'mae';
my $CGI;
my $SESSION;
my $REQUEST;


subtest 'confirm' =&gt; sub {

    my $class = 'Ean::Controller::MemberEdit';

    my $c = get_dummy_context();
    $c-&gt;session-&gt;set( navi_id =&gt; $SMART_ID );

    $c-&gt;req-&gt;param( 'navi_email_send', 1 );
    $c-&gt;req-&gt;param( 'ean_email1',      'ndds-test@example.com' );
    $c-&gt;req-&gt;param( 'ean_email1_conf', 'ndds-test@example.com' );
    $c-&gt;req-&gt;param( 'ean_email1_send', 1 );
    my $ret_data = $class-&gt;confirm($c);
    #JSONで返す型(int)もcheck
    like($ret_data, qr/&quot;ean_email2_send&quot;:1/o);
    like($ret_data, qr/&quot;show_bems_area_1&quot;:1/o);
    like($ret_data, qr/&quot;show_bems_area_2&quot;:1/o);
    like($ret_data, qr/&quot;navi_email_send&quot;:1/o);
    like($ret_data, qr/&quot;ean_email1&quot;:&quot;ndds-test\@example.com&quot;/o);
    like($ret_data, qr/&quot;ean_email1_conf&quot;:&quot;ndds-test\@example.com&quot;/o);
    like($ret_data, qr/&quot;ean_email1_send&quot;:1/o);
    like($ret_data, qr/&quot;ean_email2&quot;:&quot;ndds-test2\@example.com&quot;/o);
    like($ret_data, qr/&quot;ean_email2_conf&quot;:&quot;ndds-test2\@example.com&quot;/o);

};


sub date_str {
    my ($day_diff) = @_;
    my @date = Date::Calc::Add_Delta_Days(Date::Calc::Today, $day_diff||0);
    return sprintf(&quot;%04d-%02d-%02d&quot;, @date);
}

sub now_str {
    my ($day_diff) = @_;
    my @datetime =
        Date::Calc::Add_Delta_YMDHMS(Date::Calc::Today_and_Now,
                                     0,0,$day_diff||0, 0,0,0);
    return sprintf(&quot;%04d-%02d-%02d %02d:%02d:%02d&quot;, @datetime);
}


sub get_dummy_context {
    no strict 'refs';
    no warnings 'redefine';

    *{&quot;Ean\::session&quot;} =
        sub {
            return $SESSION if $SESSION;

            my $dummy_env = {'psgix.session'=&gt;{},
                             'psgix.session.options'=&gt;{}};
            $SESSION = Plack::Session-&gt;new( $dummy_env );
            return $SESSION;
        };
    *{&quot;Ean\::req&quot;} =
        sub {
            return $CGI if $CGI;

            $CGI = CGI-&gt;new();
            return $CGI;
        };

    *{&quot;Ean\::render_json&quot;} =
        sub {
            my ($self,$perl_obj) = @_;
            return JSON::to_json($perl_obj);
        };

    *{&quot;Ean\::request&quot;} =
        sub {
            return $REQUEST if $REQUEST;

            $REQUEST = DummyRequest-&gt;new();
            return $REQUEST;
        };

    my $c = Ean-&gt;bootstrap;
    return $c;
}


done_testing;


package DummyRequest;

sub new {
    my ($class) = @_;
    my $self = {};
    $self =  bless $self, $class;
    return $self;
}

sub cookies { return {}; }
sub env { return {}; }

__DATA__

How can JSON for perl distinguish between “string” and “numeric” ?

Standard

JSON.pm distinguish between “string” and “numeric” , and convert from perl object to json string.

#!/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}

Document of JSON describe as belog,

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::PP backend of JSON uses B module

There is source code snippet of JSON::PP.

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

You can distinguish between "string" and "numeric" too, as below.

#!/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";
        }
    }
}

“Net::SMTPS for perl” needs google application password, when using gmail smtp.

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

my $SMTP_CONF = {
    host     =&gt; 'smtp.gmail.com',
    port     =&gt; '587',
    from     =&gt; '?????@gmail.com',
    auth_uid =&gt; '?????@gmail.com',

    ### NOTICE!! application password
    ### https://myaccount.google.com/security#signin
    ### https://support.google.com/mail/answer/14257
    auth_pw  =&gt; '$APPLICATION_PASSWORD'
};

main();

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

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

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

    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 = &lt;&lt;EOF;
このメールはテストです
EOF

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

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

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

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

If you set google login password , you have error message below,

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