The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Net::FullAuto::ISets::Local::FullAutoAPI_is;

### OPEN SOURCE LICENSE - GNU AFFERO PUBLIC LICENSE Version 3.0 #######
#
#    Net::FullAuto - Powerful Network Process Automation Software
#    Copyright © 2000-2016  Brian M. Kelly
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or 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 Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public
#    License along with this program.  If not, see:
#    <http://www.gnu.org/licenses/agpl.html>.
#
#######################################################################


our $VERSION='0.01';
our $DISPLAY='FullAuto RESTful API Server';
our $CONNECT='secure';
our $defaultInstanceType='t2.small';

use 5.005;

use strict;
use warnings;

my $service_and_cert_password='Full@ut0O1';

require Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw($select_fullautoapi_setup);

use Net::FullAuto::Cloud::fa_amazon;
use Net::FullAuto::FA_Core qw[$localhost];
use File::HomeDir;
my $home_dir=File::HomeDir->my_home.'/';
my $username=getlogin || getpwuid($<);
my $do;my $ad;my $prompt;my $public_ip='';

my $configure_fullautoapi=sub {

   my $selection=$_[0]||'';
   my ($stdout,$stderr)=('','');
   my $handle=$localhost;my $connect_error='';
   $handle->cwd('~');
   my $userhome=$handle->cmd('pwd');
   my $sudo=($^O eq 'cygwin')?'':'sudo ';
$do=1;
if ($do==1) {
   unless ($^O eq 'cygwin') {
      ($stdout,$stderr)=$handle->cmd("sudo yum clean all");
      ($stdout,$stderr)=$handle->cmd("sudo yum grouplist hidden");
      ($stdout,$stderr)=$handle->cmd("sudo yum groups mark convert");
      ($stdout,$stderr)=$handle->cmd(
         "sudo yum -y groupinstall 'Development tools'",'__display__');
      ($stdout,$stderr)=$handle->cmd(
         'sudo yum -y install openssl-devel icu cyrus-sasl'.
         ' libicu cyrus-sasl-devel libtool-ltdl-devel libxml2-devel'.
         ' freetype-devel libpng-devel java-1.7.0-openjdk-devel'.
         ' unixODBC unixODBC-devel libtool-ltdl libtool-ltdl-devel'.
         ' ncurses-devel xmlto git-all','__display__');
   } else {
      my $cygcheck=`/bin/cygcheck -c` || die $!;
      my $uname=`/bin/uname` || die $!;
      my $uname_all=`/bin/uname -a` || die $!;
      $uname_all.=$uname;
      my %need_packages=();
      if ($uname_all=~/x86_64/) {
         foreach my $package ('libxml2','libxml2-devel','libtool',
               'autoconf','autobuild','automake','pkg-config',
               'libuuid-devel','wget','git','httpd',
               'httpd-mod_ssl','httpd-tools','exim') {
            unless (-1<index $cygcheck, "$package ") {
               $need_packages{$package}='';
            }
         }
      } else {
         foreach my $package ('libxml2','libxml2-devel','libtool',
               'autoconf','autobuild','automake','pkg-config',
               'libuuid-devel','wget','git','httpd','httpd-mod_ssl',
               'httpd-tools','exim') {
            unless (-1<index $cygcheck, "$package ") {
               $need_packages{$package}='';
            }
         }
      }
      # http://www.fjakkarin.com/2015/11/cygwin-cygserver-and-apache-httpd/
      ($stdout,$stderr)=$handle->cmd(
         "wget --random-wait --progress=dot ".
         "https://github.com/transcode-open/apt-cyg/archive/master.zip",
         '__display__');
      ($stdout,$stderr)=$handle->cmd("unzip -o master.zip",'__display__');
      ($stdout,$stderr)=$handle->cmd("rm -rvf master.zip",'__display__');
      ($stdout,$stderr)=$handle->cmd("mv apt-cyg-master/apt-cyg /usr/bin");
      ($stdout,$stderr)=$handle->cmd("chmod -v 755 /usr/bin/apt-cyg",
         '__display__');
      ($stdout,$stderr)=$handle->cmd("rm -rvf apt-cyg-master",'__display__');
      my $packs='';$|=1;
      foreach my $pack (sort keys %need_packages) {
         ($stdout,$stderr)=$handle->cmd("apt-cyg install $pack",
            '__display__');
         #$packs.="$pack ";
      }
      if ($^O eq 'cygwin') {
         $handle->{_cmd_handle}->print('/bin/exim-config');
         $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
         while (1) {
            my $output.=Net::FullAuto::FA_Core::fetch($handle);
            last if $output=~/$prompt/;
            print $output;
            if (-1<index $output,'local postmaster') {
               $handle->{_cmd_handle}->print();
               $output='';
               next;
            } elsif (-1<index $output,'Is it') {
               $handle->{_cmd_handle}->print('yes');
               $output='';
               next;
            } elsif (-1<index $output,'change that setting') {
               $handle->{_cmd_handle}->print('no');
               $output='';
               next;
            } elsif (-1<index $output,'standard values') {
               $handle->{_cmd_handle}->print('yes');
               $output='';
               next;
            } elsif (-1<index $output,'be links to') {
               $handle->{_cmd_handle}->print('yes');
               $output='';
               next;
            } elsif (-1<index $output,'some CPAN') {
               $handle->{_cmd_handle}->print('no');
               $output='';
               next;
            } elsif (-1<index $output,'install the exim') {
               $handle->{_cmd_handle}->print('yes');
               $output='';
               next;
            } elsif (-1<index $output,'in minutes') {
               $handle->{_cmd_handle}->print();
               $output='';
               next;
            } elsif (-1<index $output,'CYGWIN for the daemon') {
               $handle->{_cmd_handle}->print('ntsec');
               $output='';
               next;
            } elsif (-1<index $output,'the cygsla package') {
               $handle->{_cmd_handle}->print('no');
               $output='';
               next;
            } elsif (-1<index $output,'another privileged account') {
               $handle->{_cmd_handle}->print('no');
               $output='';
               next;
            } elsif (-1<index $output,'enter the password') {
               $handle->{_cmd_handle}->print($service_and_cert_password);
               $output='';
               next;
            } elsif (-1<index $output,'Reenter') {
               $handle->{_cmd_handle}->print($service_and_cert_password);
               $output='';
               next;
            } elsif (-1<index $output,'start the exim') {
               $handle->{_cmd_handle}->print('yes');
               $output='';
               next;
            }
            next;
         }
      }
      #if ($packs) {
      #   print "\n\n   Fatal Error!: The following Cygwin",
      #         "\n                 packages are missing from",
      #         "\n                 your installation:",
      #         "\n\n   $packs",
      #         "\n\n   Please report any bugs and send any",
      #         "\n   questions, thoughts or feedback to:",
      #         "\n\n      Brian.Kelly\@FullAuto.com.",
      #         "\n\n";
      #   &Net::FullAuto::FA_Core::cleanup;
      #}
      #print "\nInstalling Microsoft IIS Web Server . . .\n\n";
      # http://www.iis.net/learn/install/installing-iis-85/
      #      installing-iis-85-on-windows-server-2012-r2
      # https://technet.microsoft.com/en-us/library/hh831475.aspx
      # http://twiki.org/cgi-bin/view/TWiki/TWikiOnWindowsIISCygwin
      # https://www.iis.net/configreference/system.webserver/fastcgi
      #($stdout,$stderr)=$handle->cmd("DISM.EXE /enable-feature /all ".
      #   "/online /featureName:IIS-WebServerRole /featureName:IIS-WebServer ".
      #   "/featureName:IIS-CommonHttpFeatures /featureName:IIS-StaticContent ".
      #   "/featureName:IIS-DefaultDocument /featureName:IIS-DirectoryBrowsing ".
      #   "/featureName:IIS-HttpErrors /featureName:IIS-HttpRedirect ".
      #   "/featureName:IIS-ApplicationDevelopment /featureName:IIS-ASPNET ".
      #   "/featureName:IIS-NetFxExtensibility /featureName:IIS-ASPNET45 ".
      #   "/featureName:IIS-NetFxExtensibility45 /featureName:IIS-ASP ".
      #   "/featureName:IIS-CGI /featureName:IIS-ISAPIExtensions ".
      #   "/featureName:IIS-ISAPIFilter /featureName:IIS-ServerSideIncludes ".
      #   "/featureName:IIS-HealthAndDiagnostics /featureName:IIS-HttpLogging ".
      #   "/featureName:IIS-LoggingLibraries /featureName:IIS-RequestMonitor ".
      #   "/featureName:IIS-HttpTracing /featureName:IIS-CustomLogging ".
      #   "/featureName:IIS-ODBCLogging /featureName:IIS-Security ".
      #   "/featureName:IIS-BasicAuthentication ".
      #   "/featureName:IIS-WindowsAuthentication ".
      #   "/featureName:IIS-DigestAuthentication ".
      #   "/featureName:IIS-ClientCertificateMappingAuthentication ".
      #   "/featureName:IIS-IISCertificateMappingAuthentication ".
      #   "/featureName:IIS-URLAuthorization /featureName:IIS-RequestFiltering ".
      #   "/featureName:IIS-IPSecurity /featureName:IIS-Performance ".
      #   "/featureName:IIS-HttpCompressionStatic ".
      #   "/featureName:IIS-HttpCompressionDynamic /featureName:IIS-WebDAV ".
      #   "/featureName:IIS-WebServerManagementTools ".
      #   "/featureName:IIS-ManagementScriptingTools ".
      #   "/featureName:IIS-ManagementService ".
      #   "/featureName:IIS-IIS6ManagementCompatibility ".
      #   "/featureName:IIS-Metabase /featureName:IIS-WMICompatibility ".
      #   "/featureName:IIS-LegacyScripts /featureName:NetFx4Extended-ASPNET45 ".
      #   "/featureName:IIS-ApplicationInit /featureName:IIS-WebSockets ".
      #   "/featureName:IIS-CertProvider /featureName:IIS-ManagementConsole ".
      #   "/featureName:IIS-LegacySnapIn",'__display__');
      #($stdout,$stderr)=$handle->cmd("DISM.EXE /online /enable-feature ".
      #   "/featureName:IIS-WebServerRole /featureName:IIS-WebServer ".
      #   "/featureName:IIS-CommonHttpFeatures /featureName:IIS-StaticContent ".
      #   "/featureName:IIS-DefaultDocument /featureName:IIS-DirectoryBrowsing ".
      #   "/featureName:IIS-HttpErrors /featureName:IIS-HealthAndDiagnostics ".
      #   "/featureName:IIS-HttpLogging /featureName:IIS-Performance ".
      #   "/featureName:IIS-HttpCompressionStatic /featureName:IIS-Security ".
      #   "/featureName:IIS-RequestFiltering /featureName:IIS-CGI ".
      #   "/featureName:IIS-WebServerManagementTools ".
      #   "/featureName:IIS-ManagementConsole",'__display__');
      #my $appcmd="$ENV{WINDIR}/SYSTEM32/inetsrv";
      #($appcmd,$stderr)=$handle->cmd("cygpath -u $appcmd");
      #my $cyglocb=$handle->cmd("cygpath -w /");
      #my $cyglocw=$handle->cmd("cygpath -w ~");
      #my $cyglocwf="$cyglocw\\FullAutoAPI";
      #$cyglocw=~s/\\/\\\\/g;
      #$cyglocwf=~s/\\/\\\\/g;
      #($stdout,$stderr)=$handle->cwd($appcmd);
      #($stdout,$stderr)=$handle->cmd("pwd",'__display__');
      #my $sleep=0;
      #while (1==1) {
      #  my $ls_output=$handle->cmd("ls -1");
      #  last if -1<index $ls_output,'appcmd.exe';
      #  sleep 2;
      #  last if $sleep++>300;
      #}
      #sleep 5;
      #($stdout,$stderr)=$handle->cmd("./appcmd add site /name:FullAutoAPI ".
      #   "/id:2 /physicalPath:$cyglocwf\\root /bindings:http/*:4000",
      #   '__display__');
      #sleep 2;
      #($stdout,$stderr)=$handle->cmd("./appcmd set config -section:".
      #   "system.webServer/fastCgi /+[\"fullpath=\'$cyglocb\\script\\".
      #   "CGI_script.bat\',arguments=\'$cyglocwf\\script\\".
      #   "fullautoapi_fastcgi.pl -e\',maxInstances=\'4\',".
      #   "idleTimeout=\'300\',activityTimeout=\'30\',requestTimeout='\90\',".
      #   "instanceMaxRequests=\'1000\',protocol=\'NamedPipe\',".
      #   "flushNamedPipe=\'False\']\" /commit:apphost",'__display__');
      #sleep 2;
      #($stdout,$stderr)=$handle->cmd("./appcmd set config -section:".
      #   "system.webServer/handlers /+\"[name=\'FullAutoAPI\',".
      #   "path=\'*\',verb=\'GET,HEAD,POST\',modules=".
      #   "\'FastCgiModule\',scriptProcessor=\'$cyglocb\\script\\".
      #   "CGI_Script.bat|$cyglocwf\\script\\fullautoapi_fastcgi.pl -e\',".
      #   "resourceType=\'Unspecified\',requireAccess=\'Script\']\" ".
      #   "/commit:apphost",'__display__');
      #($stdout,$stderr)=$handle->cwd("FullAutoAPI/script");
      #($stdout,$stderr)=$handle->cmd("touch CGI_Script.bat");
      #
      # echo-ing/streaming files over ssh can be tricky. Use echo -e
      #          and replace these characters with thier HEX
      #          equivalents (use an external editor for quick
      #          search and replace - and paste back results.
      #          use copy/paste or cat file and copy/paste results.):
      #
      #          !  -   \\x21     %  -  \\x25
      #          "  -   \\x22     \  -  \\x5C
      #          $  -   \\x24
      #
      #$cyglocb=~s/\\/\\x5C/g;
      #my $content=<<END;
#$cyglocb\\x5Cbin\\x5Cbash -lc \\x22/bin/perl \\x251 \\x252\\x22
#END
      #($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > CGI_Script.bat");
      #($stdout,$stderr)=$handle->cwd("~");
      #($stdout,$stderr)=$handle->cmd("iisreset /start",'__display__');
   }
   ###############
   ## RABBITMQ
   ###############
   #($stdout,$stderr)=$handle->cmd(
   #   "wget --random-wait --progress=dot ".
   #   "https://github.com/erlang/otp/archive/maint.zip",
   #   '__display__');
   #($stdout,$stderr)=$handle->cmd("unzip -o maint.zip",'__display__');
   #($stdout,$stderr)=$handle->cmd("rm -rvf maint.zip",'__display__');
   #($stdout,$stderr)=$handle->cwd("otp-maint");
   #($stdout,$stderr)=$handle->cmd("export ERL_TOP=`pwd`",'__display__');
   #($stdout,$stderr)=$handle->cmd("./otp_build autoconf");
   #($stdout,$stderr)=$handle->cmd("./configure",'__display__');
   #($stdout,$stderr)=$handle->cmd("sudo make install",'__display__');
   #($stdout,$stderr)=$handle->cwd("..");
   #($stdout,$stderr)=$handle->cmd("sudo sed -i ".
   #   "'s#secure_path = #secure_path = /usr/local/bin:/usr/local/sbin:#'".
   #   " /etc/sudoers");
   #($stdout,$stderr)=$handle->cmd("wget -qO- ".
   #   "https://www.rabbitmq.com/download.html");
   #my $source_flag=0;
   #my $rmq='';my $rmqtar='';my $rmqdir='';
   #foreach my $line (split "\n", $stdout) {
   #   if ($line=~/Source/) {
   #      $source_flag=1;
   #   } elsif ($source_flag) {
   #      $rmq=$line;
   #      $rmq=~s/^.*href=["](.*?)["].*$/$1/;
   #      $rmq='https://www.rabbitmq.com'.$rmq;
   #      ($rmqtar=$rmq)=~s/^.*\/(.*)$/$1/;
   #      ($rmqdir=$rmqtar)=~s/^(.*).tar.gz/$1/;
   #      last;
   #   }
   #}
   #($stdout,$stderr)=$handle->cmd(
   #   "wget --random-wait --progress=dot ".$rmq,'__display__');
   #($stdout,$stderr)=$handle->cmd("tar zxvf $rmqtar",'__display__');
   #($stdout,$stderr)=$handle->cmd("rm -rvf $rmqtar",'__display__');
   #($stdout,$stderr)=$handle->cwd($rmqdir);
   #$handle->{_cmd_handle}->print('sudo su');
   #$prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   #while (1) {
   #   my $output.=Net::FullAuto::FA_Core::fetch($handle);
   #   last if $output=~/$prompt/;
   #   print $output;
   #}
   #$handle->{_cmd_handle}->print('export TARGET_DIR=/usr/local');
   #while (1) {
   #   my $output.=Net::FullAuto::FA_Core::fetch($handle);
   #   last if $output=~/$prompt/;
   #   print $output;
   #}
   #$handle->{_cmd_handle}->print('export SBIN_DIR=/usr/local');
   #while (1) {
   #   my $output.=Net::FullAuto::FA_Core::fetch($handle);
   #   last if $output=~/$prompt/;
   #   print $output;
   #}
   #$handle->{_cmd_handle}->print('export MAN_DIR=/usr/local');
   #while (1) {
   #   my $output.=Net::FullAuto::FA_Core::fetch($handle);
   #   last if $output=~/$prompt/;
   #   print $output;
   #}
   #$handle->{_cmd_handle}->print('make install');
   #while (1) {
   #   my $output.=Net::FullAuto::FA_Core::fetch($handle);
   #   last if $output=~/$prompt/;
   #   print $output;
   #}
   #$handle->{_cmd_handle}->print('exit');
   #while (1) {
   #   my $output.=Net::FullAuto::FA_Core::fetch($handle);
   #   last if $output=~/$prompt/;
   #   print $output;
   #}
   #($stdout,$stderr)=$handle->cwd("..");
   #($stdout,$stderr)=$handle->cmd(
   #   "wget --random-wait --progress=dot ".
   #   "https://github.com/rabbitmq/rabbitmq-tutorials/archive/master.zip",
   #   '__display__');
   #($stdout,$stderr)=$handle->cmd("unzip -o master.zip",'__display__');
   #($stdout,$stderr)=$handle->cmd("rm -rvf master.zip",'__display__');
   #($stdout,$stderr)=$handle->cmd("sudo rabbitmq-server -detached",
   #   '__display__');

   # TEST FOR AMAZON EC2 INSTANCE
   #($stdout,$stderr)=$handle->cmd("wget -qO- ".
   #   "wget http://169.254.169.254/latest/meta-data/public-ipv4");
   #$public_ip=$stdout if $stdout=~/^\d+\.\d+\.\d+\.\d+\s*/s;

   #unless ($public_ip) {
      ($stdout,$stderr)=$handle->cmd("wget -qO- http://icanhazip.com");
      $public_ip=$stdout if $stdout=~/^\d+\.\d+\.\d+\.\d+\s*/s;
   #}
   unless ($public_ip) {
      require Sys::Hostname;
      import Sys::Hostname;
      require Socket;
      import Socket;
      my($addr)=inet_ntoa((gethostbyname(Sys::Hostname::hostname))[4]);
      $public_ip=$addr if $addr=~/^\d+\.\d+\.\d+\.\d+\s*/s;
   }
   chomp($public_ip);
   $public_ip='localhost' unless $public_ip;
   
   unless ($^O eq 'cygwin') {
      ($stdout,$stderr)=$handle->cmd(
         "wget --random-wait --progress=dot ".
         "http://download.fedoraproject.org".
         "/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm",
         '__display__');
      ($stdout,$stderr)=$handle->cmd(
         "sudo rpm -ivh epel-release-6-8.noarch.rpm",
         '__display__');
      ($stdout,$stderr)=$handle->cmd("sudo rm -rvf epel-release-6-8.noarch.rpm",
         '__display__');
      ($stdout,$stderr)=$handle->cmd('sudo yum -y install uuid-devel '.
         'pkgconfig libtool gcc-c++','__display__');
   }
   ($stdout,$stderr)=$handle->cmd("mkdir -vp FullAutoAPI/deps",'__display__');
   ($stdout,$stderr)=$handle->cmd("mkdir -vp FullAutoAPI/root/static/images",
      '__display__');
   ($stdout,$stderr)=$handle->cmd("perl -e \'use CPAN;".
      "CPAN::HandleConfig-\>load;print \$CPAN::Config-\>{build_dir}\'");
   my $builddir=$stdout;
   my $fa_ver=$Net::FullAuto::VERSION;
   ($stdout,$stderr)=$handle->cmd(
      "ls -1t $builddir | grep Net-FullAuto-$fa_ver");
   my @lstmp=split /\n/,$stdout;
   my @ls_tmp=();
   foreach my $line (@lstmp) {
      unshift @ls_tmp, $line if $line!~/\.yml$/;
   }
   ($stdout,$stderr)=$handle->cmd("cp -v $builddir/$ls_tmp[0]/api/*py ".
      "FullAutoAPI",'__display__');
   ($stdout,$stderr)=$handle->cmd("cp -v $builddir/$ls_tmp[0]/api/*jpg ".
      "FullAutoAPI/root/static/images",'__display__');
   ($stdout,$stderr)=$handle->cmd("cp -v $builddir/$ls_tmp[0]/api/*png ".
      "FullAutoAPI/root/static/images",'__display__');
   ($stdout,$stderr)=$handle->cmd("cp -v $builddir/$ls_tmp[0]/api/*tt2 ".
      "FullAutoAPI/root",'__display__');
   ($stdout,$stderr)=$handle->cmd("cp -v $builddir/$ls_tmp[0]/demo/FA.ico ".
      "FullAutoAPI/root/favicon.ico",'__display__');
   ($stdout,$stderr)=$handle->cwd("FullAutoAPI/deps");
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "https://github.com/jedisct1/libsodium/archive/master.zip",
      '__display__');
   ($stdout,$stderr)=$handle->cmd("unzip -o master.zip",'__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}rm -rvf master.zip",'__display__');
   ($stdout,$stderr)=$handle->cwd("libsodium-master");
   ($stdout,$stderr)=$handle->cmd("./autogen.sh",'__display__');
   ($stdout,$stderr)=$handle->cmd("./configure",'__display__');
   ($stdout,$stderr)=$handle->cmd("make",'__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}make install",'__display__');
   ($stdout,$stderr)=$handle->cwd("..");
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "https://bootstrap.pypa.io/ez_setup.py",'__display__');
   if ($^O eq 'cygwin') {
      # ez_setup.py uses curl by default which is broken with --location
      # in Cygwin. So using wget instead by forcing return False.
      ($stdout,$stderr)=$handle->cmd(
         "sed -i '/has_curl()/areturn False' ez_setup.py");
      $handle->cmd_raw(
         "sed -i 's/\\(^return False$\\\)/    \\1/' ez_setup.py");
   }
   ($stdout,$stderr)=$handle->cmd("${sudo}python ez_setup.py",'__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}easy_install pip",'__display__');
   ($stdout,$stderr)=$handle->cmd(
      "git clone https://github.com/pypa/setuptools.git",'__display__');
   ($stdout,$stderr)=$handle->cwd("setuptools");
   ($stdout,$stderr)=$handle->cmd("${sudo}python setup.py install",
      '__display__');
   ($stdout,$stderr)=$handle->cwd("..");
   ($stdout,$stderr)=$handle->cmd(
      "git clone https://github.com/google/oauth2client.git",'__display__');
   ($stdout,$stderr)=$handle->cwd("oauth2client");
   ($stdout,$stderr)=$handle->cmd("${sudo}python setup.py install",
      '__display__');
   ($stdout,$stderr)=$handle->cwd("..");
   ($stdout,$stderr)=$handle->cmd("${sudo}pip install oauth2",'__display__');
   unless ($^O eq 'cygwin') {
      ($stdout,$stderr)=$handle->cmd('echo /usr/local/lib > '.
         'local.conf','__display__');
      ($stdout,$stderr)=$handle->cmd("${sudo}chmod -v 644 local.conf",
         '__display__');
      ($stdout,$stderr)=$handle->cmd(
         "${sudo}mv -v local.conf /etc/ld.so.conf.d",'__display__');
      ($stdout,$stderr)=$handle->cmd("${sudo}ldconfig");
   } else {
      ($stdout,$stderr)=$handle->cmd("pip install awscli",'__display__');
   }
}
$do=1;
if ($do==1) {
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "https://github.com/zeromq/zeromq4-1/archive/master.zip",
      '__display__');
   ($stdout,$stderr)=$handle->cmd("unzip master.zip",'__display__');
   ($stdout,$stderr)=$handle->cmd("rm -rvf master.zip",'__display__');
   ($stdout,$stderr)=$handle->cwd('zeromq4-1-master');
   ($stdout,$stderr)=$handle->cmd("./autogen.sh",'__display__');
   $handle->cmd_raw('export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig');
   ($stdout,$stderr)=$handle->cmd('./configure','__display__');
   if ($^O eq 'cygwin') {
      my $ad="        -no-undefined \\%NL%".
             "        -avoid-version \\";
      ($stdout,$stderr)=$handle->cmd(
         "sed -i \'/^libzmq_la_LDFLAGS = \\/a$ad\' ./Makefile");
      ($stdout,$stderr)=$handle->cmd( # bash shell specific
         "sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".
         "./Makefile");
   } else {
      my $ad="Defaults    env_keep += \"PKG_CONFIG_PATH\"";
      ($stdout,$stderr)=$handle->cmd(
         "sudo sed -i \'/_XKB_CHARSET/a$ad\' /etc/sudoers")
   }
   ($stdout,$stderr)=$handle->cmd('make','__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}make install",'__display__');
   ($stdout,$stderr)=$handle->cwd("..");
}
$do=1;
if ($do==1) { # NGINX
print "DOING NGINX\n";
   # https://nealpoole.com/blog/2011/04/setting-up-php-fastcgi-and-nginx
   #    -dont-trust-the-tutorials-check-your-configuration/
   # https://www.digitalocean.com/community/tutorials/
   #    understanding-and-implementing-fastcgi-proxying-in-nginx
   # http://dev.soup.io/post/1622791/I-managed-to-get-nginx-running-on
   # http://search.cpan.org/dist/Catalyst-Manual-5.9002/lib/Catalyst/
   #    Manual/Deployment/nginx/FastCGI.pod
   my $nginx='nginx-1.10.0';
   $nginx='nginx-1.9.13' if $^O eq 'cygwin';
   ($stdout,$stderr)=$handle->cmd("wget --random-wait --progress=dot ".
      "http://nginx.org/download/$nginx.tar.gz",'__display__');
   ($stdout,$stderr)=$handle->cmd("tar xvf $nginx.tar.gz",'__display__');
   ($stdout,$stderr)=$handle->cwd($nginx);
   ($stdout,$stderr)=$handle->cmd("mkdir -vp objs/lib",'__display__');
   ($stdout,$stderr)=$handle->cwd("objs/lib");
   my $pcre='pcre-8.38';
   my $checksum='';
   ($stdout,$stderr)=$handle->cmd("wget --random-wait --progress=dot ".
      "ftp://ftp.csx.cam.ac.uk/pub/software/".
      "programming/pcre/$pcre.tar.gz",'__display__');
   ($stdout,$stderr)=$handle->cmd("tar xvf $pcre.tar.gz",'__display__');
   my $zlib='zlib-1.2.8';
   ($stdout,$stderr)=$handle->cmd("wget --random-wait --progress=dot ".
      "http://zlib.net/$zlib.tar.gz",'__display__');
   $checksum='44d667c142d7cda120332623eab69f40';
   ($stdout,$stderr)=$handle->cmd("md5sum -c - <<<\"$checksum $zlib.tar.gz\"",
      '__display__');
   unless ($stderr) {
      print(qq{ + CHECKSUM Test for $zlib *PASSED* \n});
   } else {
      ($stdout,$stderr)=$handle->cmd("rm -rvf $zlib.tar.gz",'__display__');
      my $dc=1;
      print "FATAL ERROR! : CHECKSUM Test for $zlib.tar.gz *FAILED* ",
            "after $dc attempts\n";
      &Net::FullAuto::FA_Core::cleanup;
   }
   ($stdout,$stderr)=$handle->cmd("tar xvf $zlib.tar.gz",'__display__');
   my $ossl='openssl-1.0.2g';
   $checksum='36af23887402a5ea4ebef91df8e61654906f58f2';
   ($stdout,$stderr)=$handle->cmd("wget --random-wait --progress=dot ".
      "https://www.openssl.org/source/$ossl.tar.gz",
      '__display__');
   ($stdout,$stderr)=$handle->cmd("sha1sum -c - <<<\"$checksum $ossl.tar.gz\"",
      '__display__');
   unless ($stderr) {
      print(qq{ + CHECKSUM Test for $ossl *PASSED* \n});
   } else {
      ($stdout,$stderr)=$handle->cmd("rm -rvf $ossl.tar.gz",'__display__');
      my $dc=1;
      print "FATAL ERROR! : CHECKSUM Test for $ossl.tar.gz *FAILED* ",
            "after $dc attempts\n";
      &Net::FullAuto::FA_Core::cleanup;
   }
   ($stdout,$stderr)=$handle->cmd("tar xvf $ossl.tar.gz",'__display__');
   ($stdout,$stderr)=$handle->cwd("../..");
   my $make_nginx='./configure --sbin-path=/usr/local/nginx/nginx '.
                  '--conf-path=/usr/local/nginx/nginx.conf '.
                  '--pid-path=/usr/local/nginx/nginx.pid '.
                  "--with-http_ssl_module --with-pcre=objs/lib/$pcre ".
                  "--with-zlib=objs/lib/$zlib";
   ($stdout,$stderr)=$handle->cmd($make_nginx,'__display__');
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i 's/-Werror //' ./objs/Makefile");
   ($stdout,$stderr)=$handle->cmd("${sudo}make install",'__display__');
   # https://www.liberiangeek.net/2015/10/
   # how-to-install-self-signed-certificates-on-nginx-webserver/
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}mkdir -vp /etc/nginx/ssl.key");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}mkdir -vp /etc/nginx/ssl.crt");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}mkdir -vp /etc/nginx/ssl.csr");
   $handle->{_cmd_handle}->print(
      "${sudo}openssl genrsa -des3 -out ".
      "/etc/nginx/ssl.key/$public_ip.key 2048");
   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   $prompt=~s/\$$//;
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      last if $output=~/$prompt/;
      print $output;
      if (-1<index $output,'pass phrase for') {
         $handle->{_cmd_handle}->print($service_and_cert_password);
         $output='';
         next;
      } elsif (-1<index $output,'Verifying - Enter') {
         $handle->{_cmd_handle}->print($service_and_cert_password);
         $output='';
         next;
      }
   }
   while (1) {
      my $trys=0;
      my $ereturn=eval {
         local $SIG{ALRM} = sub { die "alarm\n" }; # \n required
         alarm 7;
         $handle->{_cmd_handle}->print(
            "${sudo}openssl req -new -key /etc/nginx/ssl.key/$public_ip.key ".
            "-out /etc/nginx/ssl.csr/$public_ip.csr");
         my $test='';my $output='';
         while (1) {
            $output.=Net::FullAuto::FA_Core::fetch($handle);
            $test.=$output;
            $test=~tr/\0-\11\14-\37\177-\377//d;
            return 'DONE' if $output=~/$prompt/;
            print $output;
            $test=~s/\n//gs;
            if ($test=~/Enter pass phrase.*key:/s) {
               $handle->{_cmd_handle}->print($service_and_cert_password);
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'[AU]:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'[Some-State]:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'city) []:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'Pty Ltd]:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'section) []:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'YOUR name) []:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'Address []:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'challenge password []:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            } elsif (-1<index $test,'company name []:') {
               $handle->{_cmd_handle}->print();
               $output='';
               $test='';
               next;
            }
         }
         return 'DONE';
      };
      alarm(0);
      last if $ereturn eq 'DONE' || $trys++>3;
   }
   $handle->{_cmd_handle}->print(
      "${sudo}openssl x509 -req -days 365 -in ".
      "/etc/nginx/ssl.csr/$public_ip.csr -signkey ".
      "/etc/nginx/ssl.key/$public_ip.key -out ".
      "/etc/nginx/ssl.crt/$public_ip.crt");
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      last if $output=~/$prompt/;
      print $output;
      if (-1<index $output,'Enter pass phrase') {
         $handle->{_cmd_handle}->print($service_and_cert_password);
         $output='';
         next;
      } 
   }
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i 's/1024/64/' ".
      "/usr/local/nginx/nginx.conf");
   $ad="            include fastcgi_params;%NL%".
       "            fastcgi_pass localhost:3003;";
   $ad=<<END;
sed -i '1,/location/ {/location/a\\\
$ad
}' /usr/local/nginx/nginx.conf
END
   $handle->cmd_raw("${sudo}$ad");
   ($stdout,$stderr)=$handle->cmd("${sudo}chmod 755 $home_dir");
   $ad='%NL%        location /static {'.
       "%NL%            root ${home_dir}FullAutoAPI/root;".
       '%NL%        }%NL%'.
       '%NL%        ssl on;'.
       "%NL%        ssl_certificate /etc/nginx/ssl.crt/$public_ip.crt;".
       "%NL%        ssl_certificate_key /etc/nginx/ssl.key/$public_ip.key;".
       '%NL%        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;'.
       '%NL%        ssl_ciphers '.
       '"HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";';
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/404/a$ad\' /usr/local/nginx/nginx.conf");
   ($stdout,$stderr)=$handle->cmd(
       "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".
       "/usr/local/nginx/nginx.conf");
   ($stdout,$stderr)=$handle->cmd(
       "${sudo}sed -i \'s/^        listen       80/        listen       ".
       "\*:443 ssl default_server/\' /usr/local/nginx/nginx.conf");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i 's/SCRIPT_NAME/PATH_INFO/' ".
      "/usr/local/nginx/fastcgi_params");
   $ad='# Catalyst requires setting PATH_INFO (instead of SCRIPT_NAME)'.
       ' to \$fastcgi_script_name';
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/PATH_INFO/i$ad\' /usr/local/nginx/fastcgi_params");
   $ad='fastcgi_param  SCRIPT_NAME        /;';
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/PATH_INFO/a$ad\' /usr/local/nginx/fastcgi_params");
   ($stdout,$stderr)=$handle->cmd(
       "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".
       "/usr/local/nginx/fastcgi_params");
   $handle->{_cmd_handle}->print("${sudo}/usr/local/nginx/nginx");
   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      last if $output=~/$prompt/;
      print $output;
      if (-1<index $output,'PEM pass phrase') {
         $handle->{_cmd_handle}->print($service_and_cert_password);
         $output='';
         next;
      }
   }
}
$do=0;
if ($do==1) {
   my $go=$1;my $gosha1=$2;
   ($stdout,$stderr)=$handle->cmd("wget -qO- https://golang.org/dl");
   if ($^O eq 'cygwin') {
      $stdout=~
         /^.*?href=["]([^"]+windows-amd64.zip)["].*?[<]tt[>](.*?)[<].*$/s;
      $go=$1;$gosha1=$2;
   } else {
      $stdout=~
         /^.*?href=["]([^"]+linux-amd64.tar.gz)["].*?[<]tt[>](.*?)[<].*$/s;
      $go=$1;$gosha1=$2;
   }
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".$go,
      '__display__');
   $go=~s/^.*\/(.*)$/$1/;
   ($stdout,$stderr)=$handle->cmd("sha1sum -c - <<<\"$gosha1 $go\"",
      '__display__');
   unless ($stderr) {
      print(qq{ + CHECKSUM Test for $go *PASSED* \n});
   } else {
      ($stdout,$stderr)=$handle->cmd("${sudo}rm -rvf $go",'__display__');
      print "FATAL ERROR! : CHECKSUM Test for $go *FAILED* ";
      &Net::FullAuto::FA_Core::cleanup;
   }
   if ($^O eq 'cygwin') {
      ($stdout,$stderr)=$handle->cmd("unzip -o $go",'__display__');
   } else {
      ($stdout,$stderr)=$handle->cmd("tar zxvf $go",'__display__');
   }
   ($stdout,$stderr)=$handle->cmd("rm -rvf $go",'__display__');
}
$do=0;
if ($do==1) {
   ($stdout,$stderr)=$handle->cmd('wget -qO- '.
      'https://github.com/membrane/service-proxy/releases/latest');
   $stdout=~s/^.*?href=["]([^"]+zip)["].*$/$1/s;
   my $membrane_zip=$stdout;
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot https://github.com".$membrane_zip,
      '__display__');
   $membrane_zip=~s/^.*\/(.*)$/$1/;
   ($stdout,$stderr)=$handle->cmd("unzip -o $membrane_zip",'__display__');
   ($stdout,$stderr)=$handle->cmd("rm -rvf $membrane_zip",'__display__');
   #($stdout,$stderr)=$handle->cmd('git clone --depth=1 '.
   #   'https://github.com/membrane/service-proxy.git','__display__');
exit;
}
   if ($^O eq 'cygwin') {
      #($stdout,$stderr)=$handle->cwd("~");
      $handle->{_cmd_handle}->print('cpan');
   } else {
      ($stdout,$stderr)=$handle->cmd('sudo yum -y install cpan',
         '__display__');
      $handle->{_cmd_handle}->print('sudo cpan');
   } 
   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      last if $output=~/$prompt/;
      print 'm'.$output;
      if (-1<index $output,'possible automatically') {
         $handle->{_cmd_handle}->print('yes');
         $output='';
         next;
      } elsif (-1<index $output,'by bootstrapping') {
         $handle->{_cmd_handle}->print('sudo');
         $output='';
         next;
      } elsif (-1<index $output,'some CPAN') {
         $handle->{_cmd_handle}->print('no');
         $output='';
         next;
      } elsif (-1<index $output,'pick from') {
         $handle->{_cmd_handle}->print('no');
         $output='';
         next;
      } elsif (-1<index $output,'CPAN site') {
         $handle->{_cmd_handle}->print('http://www.cpan.org');
         $output='';
         next;
      } elsif (-1<index $output,'ENTER to quit') {
         $handle->{_cmd_handle}->print();
         $output='';
         next;
      } elsif ($output=~/cpan[[]\d+[]][>]/) {
         $handle->{_cmd_handle}->print('bye');
         next;
      }
   }
   ($stdout,$stderr)=$handle->cmd("export PERL_MM_USE_DEFAULT=1");
   if ($^O eq 'cygwin') {
      my $show=<<END;
########################################

   INSTALLING Starman

########################################
END
      print $show;
      $handle->cmd_raw(
         'perl -MCPAN -e \'CPAN::Shell->notest('.
         '"install","Starman")\'',
         '__display__');
      $show=<<END;
########################################

   INSTALLING HTTP::Server::Simple

########################################
END
      print $show;
      $handle->cmd_raw(
         'perl -MCPAN -e \'CPAN::Shell->notest('.
         '"install","HTTP::Server::Simple")\'',
         '__display__');
   }
   my $show=<<END;
########################################

   INSTALLING Perl::Critic

########################################
END
      print $show;
      $handle->cmd_raw(
         'perl -MCPAN -e \'CPAN::Shell->notest('.
         '"install","Perl::Critic")\'',
         '__display__');
   $show=<<END;
########################################

   INSTALLING Devel::CheckLib

########################################
END
      print $show;
      $handle->cmd_raw(
         'perl -MCPAN -e \'CPAN::Shell->notest('.
         '"install","Devel::CheckLib")\'',
         '__display__');
   $show=<<END;
########################################

   INSTALLING ExtUtils::Embed

########################################
END
   #print $show;
   #$handle->cmd_raw(
   #   'sudo perl -MCPAN -e \'CPAN::Shell->force('.
   #   '"install","ExtUtils::Embed")\'',
   #   '__display__');
   my @cpan_modules = qw(

      Test::More
      Module::Build
      AnyEvent
      Proc::Guard
      ZMQ::LibZMQ4
      CPAN::Meta
      ExtUtils::ParseXS
      Package::Generator
      Test::Output
      Compress::Raw::Bzip2
      IO::Compress::Bzip2
      Package::Anon
      Text::Diff
      Archive::Tar
      Archive::Zip
      inc::latest
      PAR::Dist
      Regexp::Common
      Pod::Checker
      Pod::Parser
      Pod::Man
      File::Slurp
      Test::Taint
      Test::Warnings
      Test::Without::Module
      Devel::LexAlias
      BSD::Resource
      IPC::System::Simple
      Sub::Identify
      Fatal
      Sub::Name
      Role::Tiny
      Test::LeakTrace
      Test::CleanNamespaces
      Test::Pod
      Test::Pod::Coverage
      Class::Load
      Class::Load::XS
      Algorithm::C3
      SUPER
      Module::Refresh
      Declare::Constraints::Simple
      Devel::Cycle
      CGI
      Test::Memory::Cycle
      IO::String
      Mouse::Tiny
      DateTime::Format::MySQL
      Moose
      Moo
      MooseX::Role::WithOverloading
      Pod::Coverage::Moose
      MooseX::AttributeHelpers
      MooseX::ConfigFromFile
      MooseX::MarkAsMethods
      MooseX::SimpleConfig
      MooseX::StrictConstructor 
      MooseX::NonMoose
      Net::FullAuto
      Time::HiRes
      Business::ISBN
      App::FatPacker
      JSON
      JSON::XS
      Test::DistManifest
      Term::Size::Any
      Type::Tiny
      File::ReadBackwards
      Imager
      IO::CaptureOutput
      Astro::MoonPhase
      Date::Manip
      XML::LibXML
      SQL::Translator
      Template::Alloy
      URI::Amazon::APA 
      Catalyst::Runtime
      Proc::ProcessTable
      Parallel::Forker
      UUID::Tiny
      Regexp::Assemble
      Bytes::Random::Secure
      Math::Random::ISAAC::XS

   );
   # http://cygwin.1069669.n5.nabble.com/where-is-my-quot-usr-dict-
   # words-quot-or-quot-usr-share-dict-words-on-cygwin-1-7-td59328.html
   my $words="ftp://fr2.rpmfind.net/linux/fedora/linux/releases/23/".
         "Everything/i386/os/Packages/w/words-3.0-24.fc23.noarch.rpm";
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".$words,
      '__display__');
   ($stdout,$stderr)=$handle->cmd(
      "rpm2cpio words-3.0-24.fc23.noarch.rpm | \(cd /; cpio -idmv\)");
   ($stdout,$stderr)=$handle->cmd("chmod -v 755 /usr/share/dict/",
      '__display__');
   #my $pasgen="http://search.cpan.org/CPAN/authors/id/T/TJ/TJENNESS/".
   #      "Crypt-PassGen-0.06.tar.gz";
   #($stdout,$stderr)=$handle->cmd(
   #   "wget --random-wait --progress=dot ".$pasgen,
   #   '__display__');
   #($stdout,$stderr)=$handle->cmd("tar xvf Crypt-PassGen-0.06.tar.gz",
   #   '__display__');
   #($stdout,$stderr)=$handle->cwd("Crypt-PassGen-0.06");
   #($stdout,$stderr)=$handle->cmd("perl Makefile.PL",'__display__');
   #($stdout,$stderr)=$handle->cmd("make install",'__display__');
   #($stdout,$stderr)=$handle->cwd("..");
   my $install_fullautoapi=<<'END';

          o o    o .oPYo. ooooo    .oo o     o     o o    o .oPYo.
          8 8b   8 8        8     .P 8 8     8     8 8b   8 8    8
          8 8`b  8 `Yooo.   8    .P  8 8     8     8 8`b  8 8
          8 8 `b 8     `8   8   oPooo8 8     8     8 8 `b 8 8   oo
          8 8  `b8      8   8  .P    8 8     8     8 8  `b8 8    8
          8 8   `8 `YooP'   8 .P     8 8oooo 8oooo 8 8   `8 `YooP8
          ........................................................
          ::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                     _
                   ((_)
                    /
                   /              _        _           _
               \__/_     ___ __ _| |_ __ _| |_   _ ___| |_
               /    \   / __/ _` | __/ _` | | | | / __| __|  Perl MVC
            _- |    |  | (_| (_| | || (_| | | |_| \__ \ |    framework
       _ _-'   \____/   \___\__,_|\__\__,_|_|\__, |___/\__|c
     ((_)       ---\                         |___/
                    \
                     \\_          Web Framework
                      (_)

     (Catalyst Foundation is **NOT** a sponsor of the FullAuto© Project.)
END
   foreach my $module (@cpan_modules) {
      next if $module=~/^\s*#/;
      my $show=<<END;
########################################

   INSTALLING $module

########################################
END
      sleep 1;
      print $show;
      if ($module eq 'Catalyst::Runtime') {
         print $install_fullautoapi;
         sleep 10;
      }
      unless ($^O eq 'cygwin') {
         $handle->cmd_raw(
            "${sudo}LD_LIBRARY_PATH=/usr/local/lib ".
            "PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ".
            "LD_PRELOAD=/usr/local/lib/libzmq.so.5 ".
            "cpan -f -i $module",
            '__display__');
      } else {
         $handle->cmd_raw("cpan -i $module",
            '__display__');
      }
   }
   $show=<<END;
########################################

   INSTALLING Regexp::Assemble

########################################
END
#   print $show;
#   $handle->cmd_raw(
#      'sudo perl -MCPAN -e \'CPAN::Shell->force('.
#      '"install","Regexp::Assemble")\'',
#      '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Devel

########################################
END
   print $show;
   if ($^O eq 'cygwin') {
      $handle->{_cmd_handle}->print(
         'perl -MCPAN -e \'CPAN::Shell->notest('.
         '"install","Catalyst::Devel")\'');
   } else {
      $handle->{_cmd_handle}->print("${sudo}cpan Catalyst::Devel");
   }
   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      last if $output=~/$prompt/;
      print $output;
      if (-1<index $output,'XS Stash module?') {
         $handle->{_cmd_handle}->print('Y');
         $output='';
         next;
      }
      if (-1<index $output,'XS Stash by default?') {
         $handle->{_cmd_handle}->print('Y');
         $output='';
         next;
      }
   }
   $show=<<END;

########################################

   INSTALLING Crypt::PassGen

########################################
END
   $handle->cmd_raw("${sudo}cpan Crypt::PassGen",
      '__display__');
   print "\n";
   $show=<<END;

########################################

   INSTALLING Catalyst::Controller::HTML::FormFu

########################################
END
   $handle->cmd_raw("${sudo}cpan Catalyst::Controller::HTML::FormFu",
      '__display__');
   print "\n";
   $show=<<END;

########################################

   INSTALLING CatalystX::OAuth2

########################################
END
   # CatalystX::OAuth2::Schema::Result::Client
   # CatalystX::OAuth2::Schema::Result::Owner
   # CatalystX::OAuth2::Schema::Result::AccessTokenToRefreshToken
   # CatalystX::OAuth2::Schema::Result::RefreshToken
   # CatalystX::OAuth2::Schema::Result::RefreshTokenToAccessToken
   # CatalystX::OAuth2::Schema::Result::Code
   # CatalystX::OAuth2::Schema::Result::Token
   # https://metacpan.org/pod/DBIx::Class::Manual::Cookbook#Predefined-searches
   # http://ajct.info/2015/08/16/oauth-and-catalyst.html
   # http://stackoverflow.com/questions/23652166/how-to-generate-oauth-2-client-id-and-secret
   # https://bshaffer.github.io/oauth2-server-php-docs/grant-types/refresh-token/
   $handle->cmd_raw("${sudo}cpan CatalystX::OAuth2",
      '__display__');
   print "\n";
   $show=<<END;

########################################

   INSTALLING Task::Catalyst::Tutorial

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Task::Catalyst::Tutorial",'__display__');
   $show=<<END;

########################################

   INSTALLING DBIx::Class

########################################
END
   $handle->cmd_raw(
      'perl -MCPAN -e \'CPAN::Shell->notest('.
      '"install","DBIx::Class")\'',
      '__display__');
   $show=<<END;

########################################

   INSTALLING DBIx::Class::Schema::Loader

########################################
END
   $handle->cmd_raw("${sudo}cpan DBIx::Class::Schema::Loader",
      '__display__');
#   $show=<<END;
#
########################################
#
#   INSTALLING Net::RabbitFoot
#
########################################
#END
#   print $show;
#   $handle->{_cmd_handle}->print("${sudo}cpan Net::RabbitFoot");
#   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
#   while (1) {
#      my $output.=Net::FullAuto::FA_Core::fetch($handle);
#      last if $output=~/$prompt/;
#      print $output;
#      if (-1<index $output,'Skip further questions and use') {
#         $handle->{_cmd_handle}->print('y');
#         $output='';
#         next;
#      }
#   }
   $show=<<END;

########################################

   INSTALLING YAML::Syck

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan YAML::Syck",'__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Controller::REST

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Controller::REST",'__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Model::Adaptor

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Model::Adaptor",'__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::View::JSON

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::View::JSON",'__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::View::TT::Alloy

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::View::TT::Alloy",'__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Plugin::Unicode

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Plugin::Unicode",'__display__');
   $show=<<END;

########################################

   INSTALLING DBIx::Class::PassphraseColumn

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan DBIx::Class::PassphraseColumn",'__display__');
   $show=<<END;

########################################

   INSTALLING Authen::Passphrase::BlowfishCrypt

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Authen::Passphrase::BlowfishCrypt",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Method::Signatures::Simple

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Method::Signatures::Simple",
           '__display__');
   $show=<<END;

########################################

   INSTALLING HTML::FormHandler

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan HTML::FormHandler",
           '__display__');
   $show=<<END;

########################################

   INSTALLING HTML::FormHandler::Model::DBIC

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan HTML::FormHandler::Model::DBIC",
           '__display__');
   $show=<<END;

########################################

   INSTALLING CatalystX::SimpleLogin

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw(
      'perl -MCPAN -e \'CPAN::Shell->notest('.
      '"install","CatalystX::SimpleLogin")\'',
      '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Plugin::Session

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Plugin::Session",'__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Plugin::Session::Store::Memcached

########################################
END
   print $show;
   sleep 1;
   # http://vasil9v.tumblr.com/post/31921755331/compiling-memcached-on-cygwinwindows
   $handle->cmd_raw("${sudo}cpan Catalyst::Plugin::Session::Store::Memcached",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Plugin::Session::State::Cookie

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Plugin::Session::State::Cookie",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Plugin::Authentication

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Plugin::Authentication",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Authentication::Store::DBIx::Class

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Authentication::Store::DBIx::Class",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Plugin::Authorization::Roles

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Plugin::Authorization::Roles",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Time::Warp

########################################
END
   print $show;
   sleep 1;
   $handle->{_cmd_handle}->print(
      'perl -MCPAN -e \'CPAN::Shell->notest('.
      '"install","Time::Warp")\'');
   $show=<<END;

########################################

   INSTALLING DBIx::Class::TimeStamp

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan DBIx::Class::TimeStamp",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Controller::ActionRole

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Controller::ActionRole",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::ActionRole::ACL

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::ActionRole::ACL",
           '__display__');
   $show=<<END;

########################################

   INSTALLING FCGI

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan FCGI",
           '__display__');
   $show=<<END;

########################################

   INSTALLING FCGI::ProcManager

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan FCGI::ProcManager",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::Helper::Model::DBIC::Schema

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::Helper::Model::DBIC::Schema",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Catalyst::View::Email

########################################
END
   print $show;
   sleep 1;
   $handle->cmd_raw("${sudo}cpan Catalyst::View::Email",
           '__display__');
   $show=<<END;

########################################

   INSTALLING Finance::Quote

########################################
END
   print $show;
   $handle->{_cmd_handle}->print("${sudo}cpan Finance::Quote");
   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      last if $output=~/$prompt/;
      print $output;
      if (-1<index $output,'traffic to external sites') {
         $handle->{_cmd_handle}->print('Y');
         $output='';
         next;
      }
      if (-1<index $output,'have network connectivity. [n]') {
         $handle->{_cmd_handle}->print('y');
         $output='';
         next;
      }
   }
   ($stdout,$stderr)=$handle->cwd("~");
   ($stdout,$stderr)=$handle->cmd("catalyst.pl FullAutoAPI",'__display__');
   ($stdout,$stderr)=$handle->cwd("FullAutoAPI");
   ($stdout,$stderr)=$handle->cmd("perl Makefile.PL",'__display__');
   # http://www.catalystframework.org/calendar/2011/15
   # http://search.cpan.org/~bobtfish/Catalyst-Plugin-Authentication-0.10023/
   my $pm_path="./lib/FullAutoAPI.pm";
   $ad="    Session%NL%".
       "    Session::Store::Memcached%NL%".
       "    Session::State::Cookie%NL%".
       "    Authentication%NL%".
       "    Authorization::Roles%NL%".
       "    +CatalystX::SimpleLogin";
   ($stdout,$stderr)=$handle->cmd(
       "${sudo}sed -i '/    Static::Simple/a$ad' $pm_path");
   $ad="    use_request_uri_for_path => 1,%NL%".
       "    authentication => {%NL%".
       "       default_realm => %SQ%users%SQ%,%NL%".
       "       realms        => {%NL%".
       "          users => {%NL%".
       "             credential => {%NL%".
       "                class          => %SQ%Password%SQ%,%NL%".
       "                password_field => %SQ%password%SQ%,%NL%".
       "                password_type  => %SQ%self_check%SQ%%NL%".
       "             },%NL%".
       "             store => {%NL%".
       "                class         => %SQ%DBIx::Class%SQ%,%NL%".
       "                user_model    => %SQ%DB::Users%SQ%,%NL%".
       "                role_relation => %SQ%roles%SQ%,%NL%".
       "                role_field    => %SQ%name%SQ%,%NL%".
       "             }%NL%".
       "          }%NL%".
       "       },%NL%".
       "    },%NL%".
       "    %SQ%Controller::Login%SQ% => {%NL%".
       "        traits => [%SQ%-RenderAsTTTemplate%SQ%],%NL%".
       "        login_form_args => {%NL%".
       "            authenticate_args => { active => %SQ%Y%SQ% },%NL%".
       "        },%NL%".
       "    },";
   ($stdout,$stderr)=$handle->cmd(
       "${sudo}sed -i '/Send X-Catalyst header/a$ad' $pm_path");
   $handle->cmd_raw(
       "${sudo}sed -i 's/\\(^use_request_uri$\\\)/    \\1/' $pm_path");
   $handle->cmd_raw(
       "${sudo}sed -i 's/\\(^Session$\\\)/    \\1/' $pm_path");
   $handle->cmd_raw(
       "${sudo}sed -i 's/\\(^authentication =.*\\\)/    \\1/' $pm_path");
   ($stdout,$stderr)=$handle->cmd(
       "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" $pm_path");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" $pm_path");
   ($stdout,$stderr)=$handle->cmd("mkdir -vp root/login",'__display__');
   ($stdout,$stderr)=$handle->cmd("touch root/login/login.tt2",
      '__display__');
   my $content=<<'ENDD';
[% META title = 'Welcome to the FullAuto API Management Dashboard: Please Log In' %]
<div>
    [% FOR field IN login_form.error_fields %]
        [% FOR error IN field.errors %]
            <p><span style=\\x22color: red;\\x22>[% field.label _ ': ' _ error %]</span></p>
        [% END %]
    [% END %]
</div>
 
<div>
    <form id=\\x22login_form\\x22 method=\\x22post\\x22 action=\\x22[% c.req.uri %]\\x22>
        <fieldset style=\\x22border: 0;\\x22>
            <table>
                <tr>
                    <td><label class=\\x22label\\x22 for=\\x22username\\x22>Username:</label></td>
                    <td><input type=\\x22text\\x22 name=\\x22username\\x22 value=\\x22\\x22 /></td>
                </tr>
                <tr>
                    <td><label class=\\x22label\\x22 for=\\x22password\\x22>Password:</label></td>
                    <td><input type=\\x22password\\x22 name=\\x22password\\x22 value=\\x22\\x22 /></td>
                </tr>
                <tr><td><input type=\\x22submit\\x22 name=\\x22submit\\x22 value=\\x22Login\\x22 /></td></tr>
            </table>
        </fieldset>
    </form>
</div>
ENDD
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/login/login.tt2");
   ($stdout,$stderr)=$handle->cmd("mkdir -vp root/email",'__display__');
   ($stdout,$stderr)=$handle->cmd("touch root/email/welcome.tt2",
      '__display__');
   $content=<<'END';
<\\x21DOCTYPE html PUBLIC \\x22-//W3C//DTD XHTML 1.0 Transitional//EN\\x22
    \\x22http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\\x22>
<html xmlns=\\x22http://www.w3.org/1999/xhtml\\x22
      xml:lang=\\x22en\\x22
      lang=\\x22en\\x22>
<head>
</head>
<body>
<h2 align=\\x22center\\x22>Welcome to the FullAuto API Management Dashboard.</h2>
<p>Your username is: <span style=\\x22color: green;\\x22>[% username %]</span></p>
<p>Your initial password is: <span style=\\x22color: red;\\x22>[% password %]</span></p>
<p>Your client id is: <span style=\\x22color: purple;\\x22>[% client_id %]</span></p>
<p>Your client secret is: <span style=\\x22color: purple;\\x22>[% client_secret %]</span></p>
<p>You will be asked to change your password on first login.</p>
</body>
</html>
END
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/email/welcome.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/email/reset_password.tt2",
      '__display__');
   $content=<<'END';
<\\x21DOCTYPE html PUBLIC \\x22-//W3C//DTD XHTML 1.0 Transitional//EN\\x22
    \\x22http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\\x22>
<html xmlns=\\x22http://www.w3.org/1999/xhtml\\x22
      xml:lang=\\x22en\\x22
      lang=\\x22en\\x22>
<head>
</head>
<body>
<h2 align=\\x22center\\x22>Your FullAuto API Management Dashboard Password has been Reset</h2>
<p>Your username is: <span style=\\x22color: green;\\x22>[% username %]</span></p>
<p>Your password is: <span style=\\x22color: red;\\x22>[% password %]</span></p>
<p>You will be asked to change your password on first login.</p>
</body>
</html>
END
   ($stdout,$stderr)=$handle->cmd("mkdir -vp root/user",'__display__');
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/list.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/user/list.tt2",
      '__display__');
   $content=<<'END';
[% META title = 'FullAuto API: User Admin' %]
 
<br />
<a class=\\x22button\\x22 href=\\x22[% c.uri_for('/user/add') %]\\x22 onclick='this.blur();'><span>Add User</span></a>
<br />
Displaying users [% pager.first %]-[% pager.last %] of [% pager.total_entries %]
 
<table>
<tr>
    <th>Username</th>
    <th>Name</th>
    <th>Email Address</th>
    <th>Client ID</th>
    <th>Client Secret</th>
</tr>
[% WHILE (u = users.next) %]
<tr>
<td><a href=\\x22[% c.uri_for('/user', u.id, 'edit') %]\\x22>[% u.username %]</a></td>
<td>[% u.name %]</td>
<td>[% u.email_address %]</td>
<td>[% u.client_id %]</td>
<td>[% u.client_secret %]</td>
<td><a href=\\x22[% c.uri_for('/user', u.id, 'reset_password') %]\\x22>Reset Password</a></td>
<td><a href=\\x22[% c.uri_for('/user', u.id, 'inactivate') %]\\x22>Inactivate</a></td>
</tr>
[% END %]
</table>
 
&lt;&lt; 
<a href=\\x22[% c.req.uri_with({ page => pager.first_page }) %]\\x22>First</a>
<a href=\\x22[% c.req.uri_with({ page => pager.previous_page })%]\\x22>Previous</a>
|
<a href=\\x22[% c.req.uri_with({ page => pager.next_page })%]\\x22>Next</a>
<a href=\\x22[% c.req.uri_with({ page => pager.last_page }) %]\\x22>Last</a>
&gt;&gt;
END
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/list.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/user/add.tt2",
      '__display__');
   $content=<<'ENDD';
[% META title = 'FullAuto API: Add User' %]
 
<div>
<form name=\\x22[% form.name %]\\x22 action=\\x22[% c.req.uri %]\\x22 method=\\x22post\\x22>
 
[% FOR field IN form.error_fields %]
    [% FOR error IN field.errors %]
        <p><span style=\\x22color: red;\\x22>[% field.label _ ': ' _ error %]</span></p>
    [% END %]
[% END %]
 
<fieldset style=\\x22border: 0;\\x22>
<table>
<tr>
[% f = form.field('username') %]
<td><label for=\\x22[% f.name %]\\x22>[% f.label %]:</label></td>
<td><input type=\\x22text\\x22 size=30 name=\\x22[% f.name %]\\x22 id=\\x22[% f.name %]\\x22 value=\\x22[% f.fif %]\\x22></td>
</tr>
[% PROCESS user/edit_details.tt2 %]
<tr>
    <td><input type=\\x22submit\\x22 name=\\x22submit\\x22 id=\\x22submit\\x22 value=\\x22Add\\x22 /></td>
    <td><a href=\\x22/user/list\\x22>Users List</a></td>
</tr>
</fieldset>
</table>
</form>
</div>
ENDD
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/add.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/user/change_password.tt2",
      '__display__');
   $content=<<'ENDD';
[% META title = 'FullAuto API: Change Password' %]
 
<div>
<form name=\\x22[% form.name %]\\x22 action=\\x22[% c.req.uri %]\\x22 method=\\x22post\\x22>
 
[% FOR field IN form.error_fields %]
    [% FOR error IN field.errors %]
        <p><span style=\\x22color: red;\\x22>[% field.label _ ': ' _ error %]</span></p>
    [% END %]
[% END %]
 
<fieldset style=\\x22border: 0;\\x22>
<table>
[% FOREACH field_name = ['current_password', 'new_password', 'new_password_conf'] %]
<tr>
[% f = form.field(field_name) %]
<td><label for=\\x22[% f.name %]\\x22>[% f.label %]:</label></td>
<td><input type=\\x22password\\x22 name=\\x22[% f.name %]\\x22 id=\\x22[% f.name %]\\x22 value=\\x22[% f.fif %]\\x22></td>
</tr>
[% END %]
<tr><td><input type=\\x22submit\\x22 name=\\x22submit\\x22 value=\\x22Change\\x22 /></td></tr>
</fieldset>
</table>
</form>
</div>
ENDD
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/change_password.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/user/edit.tt2",
      '__display__');
   $content=<<'ENDD';
[% META title = 'FullAuto API: Edit User' %]
 
<div>
<form name=\\x22[% form.name %]\\x22 action=\\x22[% c.req.uri %]\\x22 method=\\x22post\\x22>
 
[% FOR field IN form.error_fields %]
    [% FOR error IN field.errors %]
        <p><span style=\\x22color: red;\\x22>[% field.label _ ': ' _ error %]</span></p>
    [% END %]
[% END %]
 
<fieldset style=\\x22border: 0;\\x22>
<table>
[% PROCESS user/edit_details.tt2 %]
<tr>
    <td><input type=\\x22submit\\x22 name=\\x22submit\\x22 id=\\x22submit\\x22 value=\\x22Update\\x22 /></td>
    <td><a href=\\x22/user/list\\x22>Users List</a></td>
</tr>
</fieldset>
</table>
</form>
</div>
ENDD
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/edit.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/user/edit_details.tt2",
      '__display__');
   $content=<<'ENDD';
[% FOREACH field_name = ['name', 'email_address',
                         'phone_number', 'mail_address'] %]
<tr>
[% f = form.field(field_name) %]
<td><label class=\\x22text.label\\x22 for=\\x22[% f.name %]\\x22>[% f.label %]:</label></td>
<td><input class=\\x22text\\x22 type=\\x22text\\x22 size=30 name=\\x22[% f.name %]\\x22 id=\\x22[% f.name %]\\x22 value=\\x22[% f.fif %]\\x22></td>
</tr>
[% END %]
<tr>
[% f = form.field('roles') %]
<td><label for=\\x22[% f.name %]\\x22>Roles:</label></td>
<td>[% f.render %]</td>
</tr>
ENDD
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/edit_details.tt2");
   ($stdout,$stderr)=$handle->cmd("touch root/user/profile.tt2",
      '__display__');
   $content=<<'ENDD';
[% META title = 'MyApp: User Profile' %]

<div>
<form name=\\x22[% form.name %]\\x22 action=\\x22[% c.req.uri %]\\x22 method=\\x22post\\x22>

[% FOR field IN form.error_fields %]
    [% FOR error IN field.errors %]
        <p><span style=\\x22color: red;\\x22>[% field.label _ ': ' _ error %]</span></p>
    [% END %]
[% END %]

<fieldset style=\\x22border: 0;\\x22>
<table>
[% FOREACH field_name = ['name', 'email_address',
                         'phone_number', 'mail_address'] %]
<tr>
[% f = form.field(field_name) %]
<td><label for=\\x22[% f.name %]\\x22>[% f.label %]:</label></td>
<td><input type=\\x22text\\x22 size=30 name=\\x22[% f.name %]\\x22 id=\\x22[% f.name %]\\x22 value=\\x22[% f.fif %]\\x22></td>
</tr>
[% END %]
<tr><td><input type=\\x22submit\\x22 name=\\x22submit\\x22 id=\\x22submit\\x22 value=\\x22Update\\x22 /></td></tr>
</fieldset>
</table>
</form>
</div>
ENDD
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > root/user/profile.tt2");
   ($stdout,$stderr)=$handle->cmd("mkdir -v db lib/FullAutoAPI/Schema",
      '__display__');
   ($stdout,$stderr)=$handle->cwd('db');
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "http://dev.catalyst.perl.org/repos/Catalyst/trunk/".
      "examples/RestYUI/db/adventrest.db",
      '__display__');
   ($stdout,$stderr)=$handle->cmd("mv adventrest.db fullautoapi.db");
   ($stdout,$stderr)=$handle->cwd('..');
   my $db_sql="db.sql";
   $content=<<'END';
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS roles;
DROP TABLE IF EXISTS user_roles;
DROP TABLE IF EXISTS client;
DROP TABLE IF EXISTS owner;
DROP TABLE IF EXISTS access_token_to_refresh_token;
DROP TABLE IF EXISTS refresh_token;
DROP TABLE IF EXISTS refresh_token_to_access_token;
DROP TABLE IF EXISTS code;
DROP TABLE IF EXISTS token;

CREATE TABLE token (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    code_id INTEGER NOT NULL,
    timestamp TEXT,
    FOREIGN KEY (code_id) REFERENCES code(id)
);

CREATE TABLE code (
    client_id INTEGER NOT NULL,
    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    is_active INTEGER NOT NULL DEFAULT 1,
    owner_id INTEGER,
    FOREIGN KEY (client_id) REFERENCES client(id),
    FOREIGN KEY (owner_id) REFERENCES owner(id)
);

CREATE TABLE refresh_token_to_access_token (
    access_token_id INTEGER NOT NULL UNIQUE,
    code_id INTEGER NOT NULL,
    refresh_token_id INTEGER NOT NULL UNIQUE,
    PRIMARY KEY (access_token_id, code_id, refresh_token_id),
    FOREIGN KEY (access_token_id) REFERENCES token(id),
    FOREIGN KEY (code_id) REFERENCES code(id),
    FOREIGN KEY (refresh_token_id) REFERENCES refresh_token(id)
);

CREATE TABLE refresh_token (
    id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE,
    code_id INTEGER NOT NULL,
    timestamp TEXT,
    FOREIGN KEY (code_id) REFERENCES code(id)
);

CREATE TABLE access_token_to_refresh_token (
    access_token_id INTEGER NOT NULL UNIQUE,
    code_id INTEGER NOT NULL,
    refresh_token_id INTEGER NOT NULL UNIQUE,
    PRIMARY KEY (access_token_id, code_id, refresh_token_id),
    FOREIGN KEY (access_token_id) REFERENCES token(id),
    FOREIGN KEY (code_id) REFERENCES code(id),
    FOREIGN KEY (refresh_token_id) REFERENCES refresh_token(id)
);

CREATE TABLE owner (
    id INTEGER PRIMARY KEY AUTOINCREMENT
);

CREATE TABLE client (
    id INTEGER PRIMARY KEY,
    endpoint TEXT NOT NULL,
    client_secret TEXT
);

CREATE TABLE users (
    id INTEGER PRIMARY KEY,
    active CHAR(1) NOT NULL,
    username TEXT NOT NULL UNIQUE,
    password TEXT NOT NULL,
    password_expires TIMESTAMP,
    name TEXT NOT NULL,
    email_address TEXT NOT NULL,
    phone_number TEXT,
    mail_address TEXT,
    client_id INTEGER,
    client_secret TEXT,
    FOREIGN KEY (client_id) REFERENCES client(id)
);
 
CREATE TABLE roles (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL UNIQUE
);
 
CREATE TABLE user_roles (
    user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE,
    role_id INTEGER NOT NULL REFERENCES roles(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE,
    PRIMARY KEY (user_id, role_id)
);
 
INSERT INTO users (username, active, name, email_address, password) VALUES (
    'admin', 'Y', 'Administrator', 'admin@fullauto.com', 'password'
);
INSERT INTO roles (name) VALUES ('admin');
INSERT INTO roles (name) VALUES ('can_edit');
INSERT INTO user_roles (user_id, role_id) VALUES (
    (SELECT id FROM users WHERE username = 'admin'),
    (SELECT id FROM roles WHERE name     = 'admin')
);
END
#CREATE TABLE user (
# user_id TYPE text NOT NULL PRIMARY KEY,
# fullname TYPE text NOT NULL,
# description TYPE text NOT NULL
#); 
#END
   ($stdout,$stderr)=$handle->cmd("touch $db_sql");
   ($stdout,$stderr)=$handle->cmd("chmod -v 777 $db_sql",'__display__');
   ($stdout,$stderr)=$handle->cmd("echo \"$content\" > $db_sql");
   ($stdout,$stderr)=$handle->cmd("chmod -v 644 $db_sql",'__display__');
   ($stdout,$stderr)=$handle->cmd('sqlite3 db/fullautoapi.db < db.sql');
   ($stdout,$stderr)=$handle->cmd("./script/fullautoapi_create.pl ".
      "model DB DBIC::Schema FullAutoAPI::Schema create=static ".
      "components=TimeStamp,PassphraseColumn ".
      "moniker_map='{ users => \"Users\" }' ".
      "on_connect_do='PRAGMA foreign_keys=ON' quote_char='\"' ".
      "dbi:SQLite:db/fullautoapi.db",
      '__display__');
   my $client_path="./lib/FullAutoAPI/Schema/Result/Client.pm";
   $ad="%NL%sub find_refresh {%NL%".
       "  shift->codes->search( { is_active => 1 } )%NL%".
       "    ->related_resultset(%SQ%refresh_tokens%SQ%)->find(\@_);%NL%".
       "}";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/DO NOT MODIFY THIS/a$ad' $client_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".$client_path);
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" ".
      $client_path);
   my $refreshtoken_path="./lib/FullAutoAPI/Schema/Result/RefreshToken.pm";
   $ad="%NL%".# this is a has many but will only ever return a single record%NL%".
       "# because of the constraint on the relationship table%NL%".
       "__PACKAGE__->has_many(%NL%".
       "  from_access_token_map =>%NL%".
       "    %SQ%FullAutoAPI::Schema::Result::AccessTokenToRefreshToken%SQ% => {%NL%".
       "    %SQ%foreign.refresh_token_id%SQ% => %SQ%self.id%SQ%,%NL%".
       "    %SQ%foreign.code_id%SQ%          => %SQ%self.code_id%SQ%%NL%".
       "    }%NL%".
       ");%NL%".
       "__PACKAGE__->many_to_many(%NL%".
       "  from_access_token_map_m2m => from_access_token_map => %SQ%access_token%SQ% );%NL%".
       "%NL%".
       "# this is a has many but will only ever return a single record%NL%".
       "# because of the constraint on the relationship table%NL%".
       "__PACKAGE__->has_many(%NL%".
       "  to_access_token_map =>%NL%".
       "    %SQ%FullAutoAPI::Schema::Result::RefreshTokenToAccessToken%SQ% => {%NL%".
       "    %SQ%foreign.refresh_token_id%SQ% => %SQ%self.id%SQ%,%NL%".
       "    %SQ%foreign.code_id%SQ%          => %SQ%self.code_id%SQ%%NL%".
       "    }%NL%".
       ");%NL%".
       "__PACKAGE__->many_to_many(%NL%".
       "  to_access_token_map_m2m => to_access_token_map => %SQ%access_token%SQ% );%NL%".
       "%NL%".
       "sub from_access_token { shift->from_access_token_map_m2m->first }%NL%".
       "sub to_access_token   { shift->to_access_token_map_m2m->first }%NL%".
       "%NL%".
       "sub create_access_token {%NL%".
       "  my (\$self) = \@_;%NL%".
       "  my \$code = \$self->code;%NL%".
       "  my \$token;%NL%".
       "  \$self->result_source->storage->txn_do(%NL%".
       "    sub {%NL%".
       "      # create a new token from this refresh token%NL%".
       "      \$token = \$code->tokens->create(%NL%".
       "        { from_refresh_token_map => [ { refresh_token => \$self } ] } );%NL%".
       "%NL%".
       "      # create a new refresh token and add it to the new token%NL%".
       "      my \$refresh = \$code->refresh_tokens->create( {} );%NL%".
       "      \$token->to_refresh_token_map->create(%NL%".
       "        { code => \$code, refresh_token => \$refresh } );%NL%".
       "    }%NL%".
       "  );%NL%".
       "  return \$token;%NL%".
       "}%NL%".
       "%NL%".
       "# if we have already created a token from this refresh, de-activate it".
       "%NL%%NL%".
       "sub is_active { !shift->to_access_token_map->count }%NL%".
       "%NL%".
       "sub as_string { shift->id }";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/DO NOT MODIFY THIS/a$ad' $refreshtoken_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".$refreshtoken_path);
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" ".
      $refreshtoken_path);
   $refreshtoken_path=
      "./lib/FullAutoAPI/Schema/Result/RefreshTokenToAccessToken.pm";
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i ".
      "\'s/\> \"refresh_token_id\" \}/\> \"refresh_token_id\"/\' ".
      $refreshtoken_path);
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i ".
      "\'s/\> \"access_token_id\" \}/\> \"access_token_id\"/\' ".
      $refreshtoken_path);
   $ad="    code_id => \"code_id\" },";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/\> \"refresh_token_id\",/a$ad' $refreshtoken_path");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/\> \"access_token_id\",/a$ad' $refreshtoken_path");
   $handle->cmd_raw(
       "${sudo}sed -i 's/\\(^code_id.*\\\)/    \\1/' $refreshtoken_path");
   $refreshtoken_path=
      "./lib/FullAutoAPI/Schema/Result/AccessTokenToRefreshToken.pm";
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i ".
      "\'s/\> \"refresh_token_id\" \}/\> \"refresh_token_id\"/\' ".
      $refreshtoken_path);
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i ".
      "\'s/\> \"access_token_id\" \}/\> \"access_token_id\"/\' ".
      $refreshtoken_path);
   $ad="    code_id => \"code_id\" },";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/\> \"refresh_token_id\",/a$ad' $refreshtoken_path");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/\> \"access_token_id\",/a$ad' $refreshtoken_path");
   $handle->cmd_raw(
       "${sudo}sed -i 's/\\(^code_id.*\\\)/    \\1/' $refreshtoken_path");
   my $code_path="./lib/FullAutoAPI/Schema/Result/Code.pm";
   $ad="%NL%sub as_string { shift->id }%NL%".
       "%NL%".
       "sub activate {%NL%".
       "  my(\$self, \$owner_id) = \@_;%NL%".
       "  \$self->update( { is_active => 1, owner_id => \$owner_id } )%NL%".
       "}";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/DO NOT MODIFY THIS/a$ad' $code_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".$code_path);
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" ".
      $code_path);
   my $token_path="./lib/FullAutoAPI/Schema/Result/Token.pm";
   $ad="# this is a has many but will only ever return a single record%NL%".
       "# because of the constraint on the relationship table%NL%".
       "__PACKAGE__->has_many(%NL%".
       "  from_refresh_token_map =>%NL%".
       "    %SQ%FullAutoAPI::Schema::Result::RefreshTokenToAccessToken%SQ% => {%NL%".
       "    %SQ%foreign.access_token_id%SQ% => %SQ%self.id%SQ%,%NL%".
       "    %SQ%foreign.code_id%SQ%         => %SQ%self.code_id%SQ%%NL%".
       "    }%NL%".
       ");%NL%".
       "__PACKAGE__->many_to_many(%NL%".
       "  from_refresh_token_map_m2m => from_refresh_token_map => %SQ%refresh_token%SQ% );%NL%".
       "%NL%".
       "# this is a has many but will only ever return a single record%NL%".
       "# because of the constraint on the relationship table%NL%".
       "__PACKAGE__->has_many(%NL%".
       "  to_refresh_token_map =>%NL%".
       "    %SQ%FullAutoAPI::Schema::Result::AccessTokenToRefreshToken%SQ% => {%NL%".
       "    %SQ%foreign.access_token_id%SQ% => %SQ%self.id%SQ%,%NL%".
       "    %SQ%foreign.code_id%SQ%         => %SQ%self.code_id%SQ%%NL%".
       "    }%NL%".
       ");%NL%".
       "__PACKAGE__->many_to_many(%NL%".
       "  to_refresh_token_map_m2m => to_refresh_token_map => %SQ%refresh_token%SQ% );%NL%".
       "%NL%".
       "sub from_refresh_token { shift->from_refresh_token_map_m2m->first }%NL%".
       "sub to_refresh_token   { shift->to_refresh_token_map_m2m->first }%NL%".
       "%NL%".
       "sub as_string  { shift->id }%NL%".
       "sub type       {%SQ%bearer%SQ%}%NL%".
       "sub expires_in {3600}%NL%".
       "sub owner { shift->code->owner }";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/DO NOT MODIFY THIS/a$ad' $token_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".$token_path);
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" ".
      $token_path);
   $content=<<ENDD;
package FullAutoAPI::Schema::ResultSet::Client;
use parent 'DBIx::Class::ResultSet';

sub find_refresh {
  shift->related_resultset('codes')->search( { is_active => 1 } )
    ->related_resultset('refresh_tokens')->find(\@_);
}

1;

__END__

=pod

=head1 NAME

FUllAutoAPI::Schema::ResultSet::Client

=head1 VERSION

version 0.001004

=head1 AUTHOR

Eden Cardim <edencardim\@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2015 by Suretec Systems Ltd.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
ENDD
   my $resultset_path="./lib/FullAutoAPI/Schema/ResultSet/Client.pm";
   ($stdout,$stderr)=$handle->cmd(
      "mkdir -vp ./lib/FullAutoAPI/Schema/ResultSet",'__display__');
   ($stdout,$stderr)=$handle->cmd("touch $resultset_path");
   ($stdout,$stderr)=$handle->cmd(
      "chmod -v 777 $resultset_path",'__display__');
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > $resultset_path");
   my $user_path="./lib/FullAutoAPI/Schema/Result/Users.pm";
   $ad="%NL%__PACKAGE__->add_columns(%NL%".
       "    %SQ%+password%SQ% => {%NL%".
       "        passphrase       => %SQ%rfc2307%SQ%,%NL%".
       "        passphrase_class => %SQ%BlowfishCrypt%SQ%,%NL%".
       "        passphrase_args  => {%NL%".
       "            cost        => 14,%NL%".
       "            salt_random => 20,%NL%".
       "        },%NL%".
       "        passphrase_check_method => %SQ%check_password%SQ%,%NL%".
       "    }%NL%".
       ");";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/DO NOT MODIFY THIS/a$ad' $user_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" $user_path");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" $user_path");
   ($stdout,$stderr)=$handle->cmd("./script/fullautoapi_create.pl ".
      "controller OAuth2::Provider",'__display__');
   ($stdout,$stderr)=$handle->cwd("deps");
   ($stdout,$stderr)=$handle->cmd("wget -qO- http://libevent.org/");
   $stdout=~/^.*Stable releases.*?href=["](.*?)["].*?href=["](.*?)["].*$/s;
   my $le_rel=$1;my $le_asc=$2;
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".$le_rel,'__display__');
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".$le_asc,'__display__');
   $le_rel=~s/^.*\/(.*.tar.gz)$/$1/;
   ($stdout,$stderr)=$handle->cmd("tar xvf $le_rel",'__display__');
   $le_rel=~s/.tar.gz$//;
   ($stdout,$stderr)=$handle->cwd($le_rel); 
   ($stdout,$stderr)=$handle->cmd("./configure",'__display__');
   ($stdout,$stderr)=$handle->cmd("make",'__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}make install",'__display__');
   ($stdout,$stderr)=$handle->cwd("..");
   ($stdout,$stderr)=$handle->cmd("wget -qO- http://memcached.org/");
   $stdout=~/^.*?Tar.Gz Download.*?href=["](.*?)["].*$/s;
   my $mc_rel=$1;
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".$mc_rel,'__display__');
   $mc_rel=~s/^.*\/(.*.tar.gz)$/$1/;
   ($stdout,$stderr)=$handle->cmd("tar xvf $mc_rel",'__display__');
   $mc_rel=~s/.tar.gz$//;
   ($stdout,$stderr)=$handle->cwd($mc_rel);
   ($stdout,$stderr)=$handle->cmd("./configure",'__display__'); 
   if ($^O eq 'cygwin') {
      ($stdout,$stderr)=$handle->cmd("sed -i 's/ -Werror//' Makefile");
      ($stdout,$stderr)=$handle->cmd("sed -i ".
         "'s#struct sigaction a#// struct sigaction a#' testapp.c");
      ($stdout,$stderr)=$handle->cmd("sed -i ".
         "'s#sigemptyset#// sigemptyset#' testapp.c");
      ($stdout,$stderr)=$handle->cmd("sed -i ".
         "'s#sigaction(#// sigaction(#' testapp.c");
      ($stdout,$stderr)=$handle->cmd("sed -i ".
         "'s#{ \"cache_redzone#// { \"cache_redzone#' testapp.c");
   }
   ($stdout,$stderr)=$handle->cmd("make",'__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}make install",'__display__'); 
   ($stdout,$stderr)=$handle->cwd("../..");
   #
   # echo-ing/streaming files over ssh can be tricky. Use echo -e
   #          and replace these characters with thier HEX
   #          equivalents (use an external editor for quick
   #          search and replace - and paste back results.
   #          use copy/paste or cat file and copy/paste results.):
   #
   #          !  -   \\x21
   #          "  -   \\x22
   #          $  -   \\x24
   #
   $content=<<'END';
#\\x21/usr/bin/env perl
 
use strict;
use warnings;
use lib 'lib';
 
BEGIN { \\x24ENV{CATALYST_DEBUG} = 0 }
 
use FullAutoAPI;
use DateTime;
 
my \\x24admin = FullAutoAPI->model('DB::Users')->search({ username => 'admin' })
    ->single;
 
\\x24admin->update({ password => 'admin', password_expires => DateTime->now });
END
   ($stdout,$stderr)=$handle->cmd("touch script/set_admin_password.pl");
   ($stdout,$stderr)=$handle->cmd(
      "chmod -v 777 script/set_admin_password.pl",
      '__display__');
   ($stdout,$stderr)=$handle->cmd(
      "echo -e \"$content\" > script/set_admin_password.pl");
   my $pro_path="./lib/FullAutoAPI/Controller/OAuth2/Provider.pm";
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i ".
      "\"s/Catalyst::Controller/Catalyst::Controller::ActionRole/\" ".
      $pro_path);
   $ad="%NL%".
       "with %SQ%CatalystX::OAuth2::Controller::Role::Provider%SQ%;%NL%".
       "%NL%".
       "__PACKAGE__->config(%NL%".
       "  store => {%NL%".
       "    class => %SQ%DBIC%SQ%,%NL%".
       "    client_model => %SQ%DB::Client%SQ%%NL%".
       "  }%NL%".
       ");%NL%".
       "%NL%".
       "sub request : Chained(%SQ%/%SQ%) Args(0) ".
       "Does(%SQ%OAuth2::RequestAuth%SQ%) {%NL%".
       "  my ( \$self, \$c ) = \@_;%NL%".
       "%NL%".
       "  my \$oauth2 = \$c->req->oauth2;%NL%".
       "%NL%".
       "  \$oauth2->{enable_client_secret}=0;%NL%".
       "}%NL%".
       "%NL%".
       "sub grant : Chained(%SQ%/%SQ%) Args(0) ".
       "Does(%SQ%OAuth2::GrantAuth%SQ%) {%NL%".
       "  my ( \$self, \$c ) = \@_;%NL%".
       "%NL%".
       "  my \$oauth2 = \$c->req->oauth2;%NL%".
       "%NL%".
       "  \$c->user_exists and \$oauth2->user_is_valid(1)%NL%".
       "    or \$c->detach(%SQ%/passthrulogin%SQ%);%NL%".
       "}%NL%".
       "%NL%".
       "sub token : Chained(%SQ%/%SQ%) Args(0) ".
       "Does(%SQ%OAuth2::AuthToken::ViaAuthGrant%SQ%) {%NL%".
       "  my ( \$self, \$c ) = \@_;%NL%".
       "%NL%".
       "  my \$oauth2 = \$c->req->oauth2;%NL%".
       "%NL%".
       "  \$oauth2->{refresh_token}=1;%NL%".
       "}%NL%".
       "%NL%".
       "sub refresh : Chained(%SQ%/%SQ%) Args(0) ".
       "Does(%SQ%OAuth2::AuthToken::ViaRefreshToken%SQ%) {}%NL%";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/ActionRole/a$ad' $pro_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" $pro_path");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" $pro_path");
   $content=<<'END';
name: FullAutoAPI
Model::DB:
    schema_class: FullAutoAPI::Schema
    connect_info:
        - DBI:SQLite:dbname=__path_to(db/fullautoapi.db)__
        - \\x22\\x22
        - \\x22\\x22
END
   ($stdout,$stderr)=$handle->cmd("touch fullautoapi.yml");
   ($stdout,$stderr)=$handle->cmd("chmod -v 777 fullautoapi.yml",'__display__');
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > fullautoapi.yml");
   ($stdout,$stderr)=$handle->cmd("chmod -v 644 fullautoapi.yml",'__display__');
   $content=<<'END';
<View::Email::Template>
    <sender>
        mailer Sendmail
    </sender>
    template_prefix email
    <default>
        content_type text/html
        charset utf-8
        view TT
    </default>
</View::Email::Template>
 
default_view TT
END
   ($stdout,$stderr)=$handle->cmd("chmod -v 777 fullautoapi.conf",
      '__display__');
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" >> fullautoapi.conf");
   ($stdout,$stderr)=$handle->cmd("chmod -v 644 fullautoapi.conf",
      '__display__');
   ($stdout,$stderr)=$handle->cmd(
      "./script/fullautoapi_create.pl controller User",'__display__');
   ($stdout,$stderr)=$handle->cmd("rm -rf lib/FullAutoAPI/Controller/User.pm",
      '__display__');
   my $view_path='./lib/FullAutoAPI/View/TT.pm';
   ($stdout,$stderr)=$handle->cmd(
      "./script/fullautoapi_create.pl view TT TT",'__display__');
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'s/\.tt/\.tt2/\' $view_path");
   $ad='WRAPPER => %SQ%wrapper.tt2%SQ%,';
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/render_die/a$ad\' $view_path");
   $handle->cmd_raw(
       "${sudo}sed -i 's/\\(^WRAPPER =.*\\\)/    \\1/' $view_path");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" $view_path");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" $view_path");
   ($stdout,$stderr)=$handle->cmd(
      "mkdir -vp root/static/jquery",'__display__');
   ($stdout,$stderr)=$handle->cwd('root/static/jquery');
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "https://code.jquery.com/ui/1.11.3/jquery-ui.js",
      '__display__');
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "https://code.jquery.com/jquery-1.11.3.js",
      '__display__');
   ($stdout,$stderr)=$handle->cwd('../..');
   # http://www.sitepoint.com/working-jquery-datatables/
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "https://github.com/DataTables/DataTables/archive/master.zip",
      '__display__');
   ($stdout,$stderr)=$handle->cmd('unzip -o master.zip','__display__');
   ($stdout,$stderr)=$handle->cmd("${sudo}rm -rvf master.zip",'__display__');
   ($stdout,$stderr)=$handle->cwd('DataTables-master');
   ($stdout,$stderr)=$handle->cmd('cp -Rv media ..','__display__');
   ($stdout,$stderr)=$handle->cwd('examples');
   ($stdout,$stderr)=$handle->cmd('cp -Rv resources ../..','__display__');
   ($stdout,$stderr)=$handle->cwd('../../..');
   ($stdout,$stderr)=$handle->cmd("./script/fullautoapi_create.pl ".
      "view Email::Template Email::Template",'__display__');
   #
   # echo-ing/streaming files over ssh can be tricky. Use echo -e
   #          and replace these characters with thier HEX
   #          equivalents (use an external editor for quick
   #          search and replace - and paste back results.
   #          use copy/paste or cat file and copy/paste results.):
   #
   #          !  -   \\x21
   #          "  -   \\x22
   #          $  -   \\x24
   #
   $content=<<END;
package FullAutoAPI::Controller::User;
 
use strict;
use warnings;
use Moose;
use DBI;
use namespace::autoclean;
use ZMQ::LibZMQ4;
use ZMQ::Constants qw(:all);
use JSON::XS;
use YAML;
use Carp::Assert;
use Crypt::PassGen 'passgen';
use FullAutoAPI::Form::AddUser  ();
use FullAutoAPI::Form::EditUser ();
use FullAutoAPI::Form::ChangePassword ();
use FullAutoAPI::Form::UserProfile    ();
use Math::Random::ISAAC::XS;
use Bytes::Random::Secure;

use constant NBR_WORKERS    => 2;
use constant READY          => \\x22\\\\\\\\001\\x22;

use constant FRONTEND_URL   =>
       \\x22ipc://${home_dir}FullAutoAPI/frontend.ipc\\x22;

BEGIN { extends 'Catalyst::Controller::ActionRole' }
with 'CatalystX::OAuth2::Controller::Role::WithStore';
BEGIN { extends 'Catalyst::Controller::REST' }

__PACKAGE__->config(
  store => {
    class => 'DBIC',
    client_model => 'DB::Client'
  }
);

__PACKAGE__->config(
    'default' => 'application/json',
    'map'       => {
       'text/html'          => [ 'View', 'TT' ],
       'text/xml'           => [ 'View', 'TT' ],
       'text/x-yaml'        => 'YAML',
       'application/json'   => 'JSON',
       'text/x-json'        => 'JSON',
       'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
       'text/x-data-denter' => [ 'Data::Serializer', 'Data::Denter' ],
       'text/x-data-taxi'   => [ 'Data::Serializer', 'Data::Taxi'   ],
       'application/x-storable'   => [ 'Data::Serializer', 'Storable' ],
       'application/x-freezethaw' => [ 'Data::Serializer', 'FreezeThaw' ],
       'text/x-config-general'    => [ 'Data::Serializer', 'Config::General' ],
       'application/x-www-form-urlencoded' => 'JSON',
    },
);

sub cmd : Path('/cmd') : Args(0) : ActionClass('REST') { }

sub cmd_POST : Chained('/') Args(0) Does('OAuth2::ProtectedResource') {

    my ( \\x24self, \\x24c ) = \@_;

    my \\x24auth = \\x24c->req->header('Authorization')||'';
    my ( \\x24type, \\x24token ) = split ' ', \\x24auth;

    my \\x24token_obj = \\x24self->store->verify_client_token(\\x24token);

print \\x22EXPIRES_IN=\\x22,\\x24token_obj->expires_in,\\x22\\\\\\\\n\\x22;
print \\x22TOKEN=\\x22,\\x24token,\\x22\\\\\\\\n\\x22;

    my \\x24cmd_data = '';
    my \\x24cmd = '';
    my \\x24file = '';

    if ( \\x24c->req->data ) {

print \\x22REQUEST DATA=\\x22,Data::Dump::Streamer::Dump(\\x24c->req->data)->Out(),\\x22\\\\\\\\n\\x22;

       \\x24cmd_data = \\x24c->req->data;
       unless (ref \\x24cmd_data->{'cmd'} eq 'ARRAY') {
          \\x24cmd_data->{'cmd'}=[ \\x24cmd_data->{'cmd'} ];
       }
       \\x24cmd=encode_json \\x24cmd_data->{'cmd'};
    } elsif ( \\x24c->req->uploads ) {

print \\x22REQUEST UPLOADS=\\x22,Data::Dump::Streamer::Dump(\\x24c->req->uploads)->Out(),\\x22\\\\\\\\n\\x22;

       for my \\x24field ( \\x24c->req->upload ) {
           my \\x24upload   = \\x24c->req->upload(\\x24field);
           \\x24cmd = encode_json [[ 'upload', \\x24upload->filename,
                                           \\x24upload->slurp() ]];
           last;
       }
    } else {
       return \\x24self->status_bad_request(\\x24c,
           message => 'You must provide a cmd to execute\\x21' );
    }

    my \\x24id = 'Client-'.\\x24\\x24;

    my \\x24ctx     = zmq_init();
    my \\x24socket  = zmq_socket(\\x24ctx,ZMQ_REQ);

    my \\x24rv      = zmq_setsockopt(\\x24socket,ZMQ_IDENTITY,\\x24id);
    assert(\\x24rv == 0, 'setting socket options');

    \\x24rv         = zmq_connect(\\x24socket,FRONTEND_URL());

    assert(\\x24rv == 0,'connecting client ...');

    print \\x22\\x24id sending cmd\\\\\\\\n\\x22;
    \\x24rv         = zmq_msg_send(\\x24cmd,\\x24socket);

    my \\x24reply = zmq_recvmsg(\\x24socket);

    print \\x22\\x24id got a result -> \\x22,zmq_msg_data(\\x24reply),\\x22\\\\\\\\n\\x22;

    my \\x24return_entity = {
       result     => zmq_msg_data(\\x24reply),
    };

    \\x24self->status_ok( \\x24c, entity => \\x24return_entity, );

}

sub base : Chained('/base') PathPrefix CaptureArgs(0) {}
 
sub admin : Chained('base') PathPart('') CaptureArgs(0) Does('ACL') RequiresRole('admin') ACLDetachTo('denied') {}
 
sub change_password : Chained('base') PathPart('change_password') Args(0) {
    my (\\x24self, \\x24c) = \@_;
 
    my \\x24form = FullAutoAPI::Form::ChangePassword->new;
 
    \\x24c->stash(form => \\x24form);
 
    return unless \\x24form->process(
        user   => \\x24c->user,
        params => \\x24c->req->body_parameters,
    );
 
    \\x24c->user->update({
        password         => \\x24form->field('new_password')->value,
        password_expires => undef,
    });
 
    \\x24c->res->redirect(\\x24c->uri_for('/rest/demo', {
        status_msg => 'Password changed successfully'
    }));
}

sub profile : Chained('base') PathPart('profile') Args(0) {
    my (\\x24self, \\x24c) = \@_;

    my \\x24form = FullAutoAPI::Form::UserProfile->new;

    \\x24c->stash(form => \\x24form);

    return unless \\x24form->process(
        schema  => \\x24c->model('DB')->schema,
        item_id => \\x24c->user->id,
        params  => \\x24c->req->body_parameters,
    );

    \\x24c->res->redirect(\\x24c->uri_for('/user', {
        status_msg => 'Profile Updated'
    }));
}

sub user_list : Path('/user') :Args(0) : ActionClass('REST') { }

sub user_list_GET {
    my ( \\x24self, \\x24c ) = \@_;
    my \\x24draw     = \\x24c->req->params->{draw} || 0;
    my \\x24start    = \\x24c->req->params->{start} || 0;
    my \\x24per_page = \\x24c->req->params->{length} || 10;
    my \\x24page     = 1;
    if (\\x24start<\\x24per_page) {
       \\x24page=1;
    } else {
       \\x24page=int(\\x24start/\\x24per_page)+1;
    }

    my \\x24id = 'Client-'.\\x24\\x24;

    my \\x24ctx     = zmq_init();
    my \\x24socket  = zmq_socket(\\x24ctx,ZMQ_REQ);

    my \\x24rv      = zmq_setsockopt(\\x24socket,ZMQ_IDENTITY,\\x24id);
    assert(\\x24rv == 0, 'setting socket options');

    \\x24rv         = zmq_connect(\\x24socket,FRONTEND_URL());

    assert(\\x24rv == 0,'connecting client ...');

    print \\x22\\x24id sending Hello\\\\\\\\n\\x22;
    \\x24rv         = zmq_msg_send(encode_json(['Hello']),\\x24socket);

    my \\x24reply = zmq_recvmsg(\\x24socket);

    assert(\\x24reply);

    print \\x22\\x24id got a reply -> \\x22,zmq_msg_data(\\x24reply),\\x22\\\\\\\\n\\x22;

    # We'll use an array now:
    my \@user_list;
    my \\x24rs = \\x24c->model('DB::User')
        ->search(undef, { rows => \\x24per_page })->page( \\x24page );
    while ( my \\x24user_row = \\x24rs->next ) {
        push \@user_list, {
            \\x24user_row->get_columns,
            uri => \\x24c->uri_for( '/user/' . \\x24user_row->user_id )->as_string
        };
    }

    \\x24self->status_ok( \\x24c, entity => {
        draw => \\x24draw,
        recordsTotal => \\x24rs->pager->total_entries,
        recordsFiltered => \\x24rs->pager->total_entries,
        data => [ \@user_list ]
    });
};

sub single_user : Path('/user') : Args(1) : ActionClass('REST') {
    my ( \\x24self, \\x24c, \\x24user_id ) = \@_;
 
    \\x24c->stash->{'user'} = \\x24c->model('DB::User')->find(\\x24user_id);
}

sub single_user_POST {
    my ( \\x24self, \\x24c, \\x24user_id ) = \@_;
 
    my \\x24new_user_data = \\x24c->req->data;
    if ( \\x21defined(\\x24new_user_data) ) {
       return \\x24self->status_bad_request(\\x24c,
           message => 'You must provide a user to create or modify\\x21' );
    }

    if ( \\x24new_user_data->{'user_id'} ne \\x24user_id ) {
       return \\x24self->status_bad_request( 
              \\x24c,
              message => 
                 'Cannot create or modify user '
                 . \\x24new_user_data->{'user_id'} . ' at '
                 . \\x24c->req->uri->as_string
                 . '; the user_id does not match\\x21' );
    }

    foreach my \\x24required (qw(user_id fullname description)) {
       return \\x24self->status_bad_request( \\x24c,
          message => 'Missing required field: ' . \\x24required )
       if \\x21exists( \\x24new_user_data->{\\x24required} );
    }

    my \\x24user = \\x24c->model('DB::User')->update_or_create(
       user_id     => \\x24new_user_data->{'user_id'},
       fullname    => \\x24new_user_data->{'fullname'},
       description => \\x24new_user_data->{'description'},
    );
    my \\x24return_entity = {
       user_id     => \\x24user->user_id,
       fullname    => \\x24user->fullname,
       description => \\x24user->description,
    };

    if ( \\x24c->stash->{'user'} ) {
        \\x24self->status_ok( \\x24c, entity => \\x24return_entity, );
    } else {
        \\x24self->status_created(
            \\x24c,
            location => \\x24c->req->uri->as_string,
            entity   => \\x24return_entity,
        );
    }
}

*single_user_PUT = *single_user_POST;

sub single_user_GET {
    my ( \\x24self, \\x24c, \\x24user_id ) = \@_;
 
    my \\x24user = \\x24c->stash->{'user'};
    if ( defined(\\x24user) ) {
        \\x24self->status_ok(
            \\x24c,
            entity => {
                user_id     => \\x24user->user_id,
                fullname    => \\x24user->fullname,
                description => \\x24user->description,
            }
        );
    }
    else {
        \\x24self->status_not_found( \\x24c,
            message => 'Could not find User '.\\x24user_id.'\\x21' );
    }
}

sub single_user_DELETE {
    my ( \\x24self, \\x24c, \\x24user_id ) = \@_;
 
    my \\x24user = \\x24c->stash->{'user'};
    if ( defined(\\x24user) ) {
        \\x24user->delete;
        \\x24self->status_ok(
            \\x24c,
            entity => {
                user_id     => \\x24user->user_id,
                fullname    => \\x24user->fullname,
                description => \\x24user->description,
            }
        );
    } else {
        \\x24self->status_not_found( \\x24c,
        message => 'Cannot delete non-existent user '.\\x24user_id.'\\x21' );
    }
}

sub list : Chained('admin') PathPart('list') Args(0) {
    my (\\x24self, \\x24c) = \@_;
 
    my \\x24users = \\x24c->model('DB::Users')->search(
        { active => 'Y'},
        {
            order_by => ['username'],
            page     => (\\x24c->req->param('page') || 1),
            rows     => 20,
        }
    );
 
    \\x24c->stash(
        users => \\x24users,
        pager => \\x24users->pager,
    );
}
 
sub add : Chained('admin') PathPart('add') Args(0) {
    my (\\x24self, \\x24c) = \@_;
 
    my \\x24form = FullAutoAPI::Form::AddUser->new;
 
    \\x24c->stash(form => \\x24form);
 
    my \\x24user = \\x24c->model('DB::Users')->new_result({});
    my \\x24client = \\x24c->model('DB::Client')->new_result({});

    my (\\x24temp_password) = passgen(NWORDS => 1, NLETT => 8);
 
    \\x24user->password(\\x24temp_password);
    \\x24user->password_expires(DateTime->now);
    \\x24user->active('Y');
 
    return unless \\x24form->process(
        schema => \\x24c->model('DB')->schema,
        item   => \\x24user,
        params => \\x24c->req->body_parameters,
    );

    my \\x24client_id=\\x24user->id.time();
    \\x24user->client_id(\\x24client_id);
    \\x24client->id(\\x24client_id);
    \\x24client->endpoint('/cmd');
    my \\x24secret=Bytes::Random::Secure::random_bytes_base64(30);
    \\x24user->client_secret(\\x24secret);
    \\x24user->update;
    \\x24client->client_secret(\\x24secret);
    \\x24client->insert;
 
    \\x24c->stash->{email} = {
        to           => \\x24user->email_address,
        from         => 'admin\@MyOrg.com',
        subject      => 'Welcome to the FullAuto API',
        content_type => 'text/html',
        template     => 'email/welcome.tt2',
    };
 
    \\x24c->stash(
        username => \\x24user->username,
        password => \\x24temp_password,
        client_id => \\x24client->id,
        client_secret => \\x24client->client_secret,
    );
 
    \\x24c->forward(\\x24c->view('Email::Template'));
 
    \\x24c->res->redirect(\\x24c->uri_for(\\x24self->action_for('list'), {
        status_msg => 'User '
            . \\x24user->username
            . ' created successfully'
            . ', initial password emailed ' . 'to '
            . \\x24user->email_address
    }));
}
 
sub user : Chained('admin') PathPart('') CaptureArgs(1) {
    my (\\x24self, \\x24c, \\x24user_id) = \@_;
 
    \\x24c->stash(user => \\x24c->model('DB::Users')->find(\\x24user_id));
}
 
sub inactivate : Chained('user') PathPart('inactivate') Args(0) {
    my (\\x24self, \\x24c) = \@_;
 
    my \\x24user = \\x24c->stash->{user};
 
    \\x24user->update({ active => 'N' });
 
    my \\x24username = \\x24user->username;
 
    \\x24c->res->redirect(\\x24c->uri_for(\\x24self->action_for('list'), {
        status_msg => \\x22User \\x24username inactivated\\x22
    }));
}
 
sub reset_password : Chained('user') PathPart('reset_password') Args(0) {
    my (\\x24self, \\x24c) = \@_;
 
    my \\x24user = \\x24c->stash->{user};
 
    my (\\x24temp_password) = passgen(NWORDS => 1, NLETT => 8);
 
    \\x24user->password(\\x24temp_password);
    \\x24user->password_expires(DateTime->now);
    \\x24user->update;
 
    \\x24c->stash->{email} = {
        to           => \\x24user->email_address,
        from         => 'admin\@MyOrg.com',
        subject      => 'Your FullAuto API Management Dashboard Password has been Reset',
        content_type => 'text/html',
        template     => 'reset_password.tt2',
    };
 
    \\x24c->stash(
        username => \\x24user->username,
        password => \\x24temp_password,
    );
 
    \\x24c->forward(\\x24c->view('Email::Template'));
 
    \\x24c->res->redirect(\\x24c->uri_for(\\x24self->action_for('list'), {
        status_msg => 'Password reset email for '
            . \\x24user->username
            . ' sent to '
            . \\x24user->email_address
    }));
}
 
sub edit : Chained('user') PathPart('edit') Args(0) {
    my (\\x24self, \\x24c) = \@_;
 
    my \\x24form = FullAutoAPI::Form::EditUser->new;
 
    \\x24c->stash(form => \\x24form);
 
    return unless \\x24form->process(
        schema  => \\x24c->model('DB')->schema,
        item_id => \\x24c->stash->{user}->id,
        params  => \\x24c->req->body_parameters,
    );
 
    \\x24c->res->redirect(\\x24c->uri_for(\\x24self->action_for('list'), {
        status_msg => 'User '
            . \\x24c->stash->{user}->username
            . ' updated successfully'
    }));
}

sub denied : Private {
    my (\\x24self, \\x24c) = \@_;
 
    \\x24c->res->redirect(\\x24c->uri_for('/rest/demo', {
        status_msg => \\x22Access Denied\\x22
    }));
}

1;
END
   ($stdout,$stderr)=$handle->cwd('lib/FullAutoAPI/Controller');
   ($stdout,$stderr)=$handle->cmd("touch User.pm");
   ($stdout,$stderr)=$handle->cmd("chmod -v 777 User.pm",'__display__');
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > User.pm");
   $content=<<END;
package FullAutoAPI::Controller::Rest;
use Moose;
use namespace::autoclean;

BEGIN {extends 'Catalyst::Controller::ActionRole'; }

sub base : Chained('/base') PathPrefix CaptureArgs(0) {}

sub rest : Chained('base') PathPart('demo') Args(0) {
    my (\\x24self, \\x24c) = \@_;

    \\x24c->stash(template => 'rest/demo.tt2');
}

sub denied : Private {
    my (\\x24self, \\x24c) = \@_;

    \\x24c->res->redirect(\\x24c->uri_for(\\x24self->action_for('rest'),
        {status_msg => \\x22Access Denied\\x22}));
}

__PACKAGE__->meta->make_immutable;

1;
END
   ($stdout,$stderr)=$handle->cmd("touch Rest.pm");
   ($stdout,$stderr)=$handle->cmd("chmod -v 777 Rest.pm",'__display__');
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > Rest.pm");
   $ad='sub home : Chained(%SQ%/base%SQ%) PathPart(%SQ%%SQ%) Args(0) {'.
       '%NL%    my ($self, $c) = @_;%NL%%NL%'.
       '    $c->res->redirect($c->uri_for(%SQ%/rest/demo%SQ%));%NL%'.
       '}%NL%%NL%';
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/sub index :Path/i$ad\' ./Root.pm");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i '/index :Path :/,+6d' ./Root.pm");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i 's/index/home/' ./Root.pm");
   $ad='%NL%sub base : Chained(%SQ%/login/required%SQ%) PathPrefix '.
       'CaptureArgs(0) {%NL%'.
       '    my ($self, $c) = @_;%NL%'.
       '%NL%'.
       '    if ($c->action ne $c->controller(%SQ%User%SQ%)->action_for('.
       '%SQ%change_password%SQ%)%NL%'.
       '        && $c->user_exists%NL%'.
       '        && $c->user->password_expires%NL%'.
       '        && $c->user->password_expires <= DateTime->now)%NL%'.
       '    {%NL%        '.
       '$c->res->redirect($c->uri_for(%SQ%/user/change_password%SQ%, {%NL%'.
       '            status_msg => %SQ%Password Expired%SQ%%NL%'.
       '        }));%NL%'.
       '        $c->detach;%NL%'.
       '    }%NL%'.
       '}%NL%';
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/home : Chained/i$ad\' ./Root.pm");
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i 's#default :Path#default : Chained(%SQ%/base%SQ%) ".
      "PathPart(%SQ%%SQ%) Args#' ./Root.pm");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ./Root.pm");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" ./Root.pm");
   ($stdout,$stderr)=$handle->cwd("..");
   ($stdout,$stderr)=$handle->cmd("mkdir -vp Form");
   ($stdout,$stderr)=$handle->cwd("Form");
   $content=<<END;
package FullAutoAPI::Form::AddUser;

use HTML::FormHandler::Moose;
extends 'FullAutoAPI::Form::EditUser';
use namespace::autoclean;

has_field 'username' => (
    type     => 'Text',
    label    => 'User name',
    required => 1,
);

__PACKAGE__->meta->make_immutable;

1;
END
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > AddUser.pm");
   $content=<<END;
package FullAutoAPI::Form::ChangePassword;

use HTML::FormHandler::Moose;
extends 'HTML::FormHandler';
use namespace::autoclean;
use Method::Signatures::Simple;

has user => (is => 'rw');

has_field 'current_password' => (
   type     => 'Password',
   label    => 'Current Password',
   required => 1,
);

method validate_current_password(\\x24field) {
    \\x24field->add_error('Incorrect password')
        if not \\x24self->user->check_password(\\x24field->value);
}

has_field 'new_password' => (
    type      => 'Password',
    label     => 'New Password',
    required  => 1,
    minlength => 5,
);

after validate => method {
    if (\\x24self->field('new_password')->value eq
            \\x24self->field('current_password')->value )
    {
        \\x24self->field('new_password')
            ->add_error('Must be different from current password');
    }
};

has_field 'new_password_conf' => (
   type           => 'PasswordConf',
   label          => 'New Password (again)',
   password_field => 'new_password',
   required       => 1,
   minlength      => 5,
);

has_field submit => (type => 'Submit', value => 'Change');

__PACKAGE__->meta->make_immutable;

1;
END
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > ChangePassword.pm");
   $content=<<END;
package FullAutoAPI::Form::EditUser;

use HTML::FormHandler::Moose;
extends 'FullAutoAPI::Form::UserProfile';
use namespace::autoclean;

has_field 'roles' => (
    type         => 'Multiple',
    widget       => 'checkbox_group',
    label_column => 'name',
    label        => '',
);

__PACKAGE__->meta->make_immutable;

1;
END
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > EditUser.pm");
   $content=<<END;
package FullAutoAPI::Form::UserProfile;

use HTML::FormHandler::Moose;
extends 'HTML::FormHandler::Model::DBIC';
use namespace::autoclean;

has '+item_class' => (default => 'Users');

has_field 'name'          => ( type => 'Text',  required => 1 );
has_field 'email_address' => ( type => 'Email', required => 1 );
has_field 'phone_number'  => ( type => 'Text' );
has_field 'mail_address'  => ( type => 'Text' );

has_field submit => (
   type  => 'Submit',
   value => 'Update'
);

__PACKAGE__->meta->make_immutable;

1;
END
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > UserProfile.pm");
   ($stdout,$stderr)=$handle->cmd("chmod -v 644 User.pm",'__display__');
   ($stdout,$stderr)=$handle->cwd('../../../root/static');
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "http://dev.catalyst.perl.org/repos/Catalyst/trunk/".
      "examples/RestYUI/root/static/json2.js",
      '__display__');
   ($stdout,$stderr)=$handle->cmd('mkdir -vp yui','__display__');
   ($stdout,$stderr)=$handle->cwd('yui');
   my @yuifiles=('utilities.js','dom.js','connection.js','event.js',
                 'yahoo.js');
   foreach my $file (@yuifiles) {
      ($stdout,$stderr)=$handle->cmd(
         "wget --random-wait --progress=dot ".
         "http://dev.catalyst.perl.org/repos/Catalyst/trunk/".
         "examples/RestYUI/root/static/yui/$file",
         '__display__');
   }
   ($stdout,$stderr)=$handle->cwd('../..');
   ($stdout,$stderr)=$handle->cmd('mkdir -vp user','__display__');
   ($stdout,$stderr)=$handle->cwd('user');
   ($stdout,$stderr)=$handle->cmd(
      "wget --random-wait --progress=dot ".
      "http://dev.catalyst.perl.org/repos/Catalyst/trunk/".
      "examples/RestYUI/root/user/single_user.tt",
      '__display__');
   ($stdout,$stderr)=$handle->cmd(
      "sed -i 's/POSTT/POST/' single_user.tt");
   ($stdout,$stderr)=$handle->cmd(
      "mv single_user.tt single_user.tt2");
   ($stdout,$stderr)=$handle->cwd('..');
   ($stdout,$stderr)=$handle->cmd('mkdir -vp rest','__display__');
   ($stdout,$stderr)=$handle->cwd('rest');
   #
   # echo-ing/streaming files over ssh can be tricky. Use echo -e
   #          and replace these characters with thier HEX
   #          equivalents (use an external editor for quick
   #          search and replace - and paste back results.
   #          use copy/paste or cat file and copy/paste results.):
   #
   #          !  -   \\x21
   #          "  -   \\x22
   #          $  -   \\x24
   #
   $content=<<END;
<\\x21DOCTYPE html>
<html>
<head>
   <meta charset=\\x22utf-8\\x22>
   <meta name=\\x22viewport\\x22 content=\\x22initial-scale=1.0, maximum-scale=2.0\\x22>

   <title>Catalyst REST Example</title>

   <link rel=\\x22stylesheet\\x22 type=\\x22text/css\\x22 href=\\x22https://cdn.datatables.net/1.10.8/css/jquery.dataTables.min.css\\x22>
   <link rel=\\x22stylesheet\\x22 type=\\x22text/css\\x22 href=\\x22resources/demo.css\\x22></script>
   <script type=\\x22text/javascript\\x22 language=\\x22javascript\\x22 src=\\x22//code.jquery.com/jquery-1.11.3.min.js\\x22></script>
   <script type=\\x22text/javascript\\x22 language=\\x22javascript\\x22 src=\\x22https://cdn.datatables.net/1.10.8/js/jquery.dataTables.min.js\\x22></script>
   <script type=\\x22text/javascript\\x22 language=\\x22javascript\\x22 class=\\x22init\\x22>

   \\x24(document).ready(function() {
      \\x24(\\x22#example\\x22).dataTable({
         \\x22processing\\x22: true,
         \\x22serverSide\\x22: true,
         \\x22ajax\\x22: \\x22[%c.uri_for( c.controller('User').action_for('user_list') ) %]?page=1&content-type=application/json\\x22,
         \\x22aoColumns\\x22: [{
            \\x22mData\\x22:\\x22user_id\\x22,
         },{
            \\x22mData\\x22: \\x22fullname\\x22,
         },{
            \\x22mData\\x22: \\x22description\\x22,
         }]
     });
   } );

  </script>
</head>

<body class=\\x22dt-example\\x22>
   <div class=\\x22container\\x22>
      <section>
         <h1>Catalyst REST Example <span>Using JQuery DataTable</span></h1>

         <div class=\\x22info\\x22>
            <p>FullAuto was used to stand up this fully functional Catalyst REST installation.
               The following table is full of demo user data. To add or update a user, manually
               modify the browser URL like so:

            <br><br><code>[%c.uri_for( c.controller('User').action_for('user_list') ) %]/user_id</code></p>

            <p>Data can be accessed on the command line:
                <br><br><code>curl -X GET -k -H 'Content-Type: application/json'
                [%c.uri_for( c.controller('User').action_for('user_list') ) %]</code>
                <br><br><code>
                curl -X GET -k 
                \\x22[% c.req.base %]request?client_id=&lt;client_id&gt;&response_type=code&redirect_uri=/cmd\\x22
                </code><br><br><code>
                curl -X GET -k
                \\x22[% c.req.base %]/token?grant_type=authorization_code&client_id=&lt;client_id&gt;&redirect_uri=/cmd&code=&lt;code&gt;\\x22
                </code><br><br><code>
                curl -X POST -k -H 'Authorization: Bearer &lt;token&gt;'
                -H 'Content-Type: application/json'
                -d '{\\x22cmd\\x22:\\x22hostname\\x22}'
                [% c.req.base %]cmd
                </code></p>
         </div>
            <table id=\\x22example\\x22 class=\\x22display\\x22 cellspacing=\\x220\\x22 width=\\x22100%\\x22>
               <thead>
                  <tr>
                     <th>ID</th>
                     <th>Full Name</th>
                     <th>Description</tn>
                  </tr>
               </thead>

               <tfoot>
                  <tr>
                     <th>ID</th>
                     <th>Full Name</th>
                     <th>Description</th>
                  </tr>
               </tfoot>
            </table>
         </div>
      </section>
   </div>
</body>
</html>
END
   ($stdout,$stderr)=$handle->cmd("echo -e \"$content\" > demo.tt2");
   ($stdout,$stderr)=$handle->cwd('../..');
   $ad="use Net::FullAuto;%NL%".
       "use Net::FullAuto::Cloud::fa_amazon;%NL%".
       "use ZMQ::LibZMQ4;%NL%".
       "use ZMQ::Constants qw(:all);%NL%".
       "use JSON::XS;%NL%".
       "use YAML;%NL%".
       "use Carp::Assert;%NL%".
       "use Crypt::PassGen %SQ%passgen%SQ%;%NL%".
       "use Math::Random::ISAAC::XS;%NL%".
       "use Bytes::Random::Secure;%NL%%NL%".
       "use constant NBR_WORKERS    => 2;%NL%".
       "use constant READY          => \"\\\\001\";%NL%".
       "%NL%".
       "use constant BACKEND_URL    =>%NL%".
       "       %SQ%ipc://${home_dir}FullAutoAPI/backend.ipc%SQ%;%NL%".
       "use constant FRONTEND_URL    =>%NL%".
       "       %SQ%ipc://${home_dir}FullAutoAPI/frontend.ipc%SQ%;%NL%".
       "%NL%".
       "use Parallel::Forker;%NL%".
       "%NL%".
       "system(\"nohup /usr/local/bin/memcached >> /dev/null 2>&1 &\");%NL%".
       "%NL%".
       "my \$fa_sub=sub {%NL%".
       "%NL%".
       "   my \$server={%NL%".
       "%NL%".
       "      Label => %SQ%server%SQ%,%NL%".
       "      LoginID => %SQ%${username}%SQ%,%NL%".
       "      IdentityFile => %SQ%${home_dir}FullAutoAPI/fullauto.pem%SQ%,%NL%".
       "      HostName => %SQ%localhost%SQ%,%NL%".
       "%NL%".
       "   };%NL%".
       "   # A bit of custom config riding/hacking to use the application".
       "%SQ%s%NL%".
       "   # config for the DB.%NL%".
       "   my \$config_file = %SQ%${home_dir}FullAutoAPI/fullautoapi.yml".
       "%SQ%;%NL%".
       "   my \$config_data = YAML::LoadFile( \$config_file );%NL%".
       "   #my \$args = \$config_data->{\"Model::ZeroMQ\"}->{args};%NL%".
       "%NL%".
       "   my \$id = %SQ%Worker-%SQ%.\$\$;%NL%%NL%".
       "   my \$ctx     = zmq_init();%NL%".
       "   my \$socket  = zmq_socket(\$ctx,ZMQ_REQ);%NL%%NL%".
       "   my \$rv      = zmq_setsockopt(\$socket,ZMQ_IDENTITY,\$id);%NL%".
       "   assert(\$rv == 0);%NL%%NL%".
       "   \$rv         = zmq_connect(\$socket,BACKEND_URL());%NL%".
       "   assert(\$rv == 0,%SQ%connecting to backend%SQ%);%NL%%NL%".
       "   print \"\$id sending READY\\n\";%NL%".
       "%NL%".
       "   \$rv = zmq_msg_send(READY(),\$socket);%NL%".
       "   assert(\$rv);%NL%".
       "%NL%".
       "   my \$buf = zmq_msg_init();%NL%".
       "%NL%".
       "   my (\$fullauto,\$stdout,\$stderr,\$exitcode,".
       "\$connect_error)=(%SQ%%SQ%,%SQ%%SQ%,%SQ%%SQ%,%SQ%%SQ%,%SQ%%SQ%);%NL%".
       "   (\$fullauto,\$connect_error)=connect_shell(\$server);%NL%".
       "%NL%".
       "   use Time::HiRes;%NL%".
       "   # http://www.unitconversion.org/unit_converter/time-ex.html%NL%".
       "   my \$msg = zmq_msg_init();%NL%".
       "   my \$handles={};%NL%".
       "   while (1) {%NL%".
       "%NL%".
       "      my \@msg=();%NL%".
       "      if (zmq_msg_recv(\$buf,\$socket,ZMQ_DONTWAIT)) {%NL%".
       "         push \@msg, zmq_msg_data(\$buf);%NL%".
       "         while (zmq_getsockopt(\$socket,ZMQ_RCVMORE)) {%NL%".
       "            zmq_msg_recv(\$buf,\$socket);%NL%".
       "            push \@msg, zmq_msg_data(\$buf);%NL%".
       "         }%NL%".
       "      }%NL%".
       "      if (getppid==1) {%NL%".
       "         `pgrep -P \$\$ | xargs kill -TERM`;%NL%".
       "         exit;%NL%".
       "      }%NL%".
       "      if (\$#msg) {%NL%".
       "         print \"\$id got: \$msg[2] from \$msg[0]\\n\";%NL%".
       "         print \"\$id sending OK to \$msg[0]\\n\";%NL%".
       "         zmq_msg_send(\$msg[0],\$socket,ZMQ_SNDMORE);%NL%".
       "         zmq_msg_send(%SQ%%SQ%,\$socket,ZMQ_SNDMORE);%NL%".
       "         my \$cmds=decode_json \$msg[2];%NL%".
       "         if (\$cmds->[0] eq %SQ%Hello%SQ%) {%NL%".
       "            zmq_msg_send(encode_json([%SQ%Hello Back%SQ%]),%NL%".
       "               \$socket);%NL%".
       "            next;%NL%".
       "         }%NL%".
       "         \$cmds=[\$cmds] unless ref \$cmds eq %SQ%ARRAY%SQ%;%NL%".
       "         my \$out=[];%NL%".
       "         foreach my \$cmd (\@{\$cmds}) {%NL%".
       "            if (ref \$cmd eq %SQ%ARRAY%SQ%) {%NL%".
       "               if (\$cmd->[0] eq %SQ%cmd%SQ%) {%NL%".
       "                  (\$stdout,\$stderr)=\$fullauto->cmd(%NL%".
       "                     \$cmd->[1]);%NL%".
       "                  push \@{\$out},[\$stdout,\$stderr]%NL%".
       "               } elsif (\$cmd->[0] eq %SQ%cmd_raw%SQ%) {%NL%".
       "                  (\$stdout,\$stderr)=\$fullauto->cmd_raw(%NL%".
       "                     \$cmd->[1]);%NL%".
       "                  push \@{\$out},[\$stdout,\$stderr]%NL%".
       "               } elsif (\$cmd->[0] eq %SQ%cwd%SQ%) {%NL%".
       "                  (\$stdout,\$stderr)=\$fullauto->cwd(%NL%".
       "                     \$cmd->[1]);%NL%".
       "                  push \@{\$out},[\$stdout,\$stderr]%NL%".
       "               } elsif (\$cmd->[0] eq %SQ%aws_configure%SQ%) {%NL%".
       "                  my \$key=\$cmd->[1];%NL%".
       "                  my \$secret=\$cmd->[2];%NL%".
       "                  \$aws_configure->(\$key,\$secret);%NL%".
       "               } elsif (\$cmd->[0] eq %SQ%upload%SQ%) {%NL%".
       "                  open(FH,\">/tmp/\$cmd->[1]\") || warn \$!;%NL%".
       "                  print FH \$cmd->[2];%NL%".
       "                  close FH;%NL%".
       "               } elsif (\$cmd->[0] eq %SQ%label%SQ%) {%NL%".
       "                  print \"LABEL=\".\$cmd->[1]->[0];%NL%".
       "                  if (exists \$handles->{\$cmd->[1]->[0]}) {%NL%".
       "                     if (\$cmd->[1]->[1] eq %SQ%cmd%SQ%) {%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->cmd(%NL%".
       "                           \$cmd->[1]->[2]);%NL%".
       "                        push \@{\$out},[\$stdout,\$stderr]%NL%".
       "                     } elsif (\$cmd->[1]->[0] eq %SQ%close%SQ%) {%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->close();%NL%".
       "                        delete \$handles->{\$cmd->[1]->[0]};%NL%".
       "                        \$stdout=\"\$cmd->[1]->[0] CLOSED\";%NL%".
       "                        push \@{\$out},[\$stdout,\$stderr]%NL%".
       "                     } elsif (\$cmd->[1]->[1] eq 'docker_run') {%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->docker_run(%NL%".
       "                           \$cmd->[1]->[2]);%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->cmd(%NL%".
       "                           %SQ%hostname%SQ%);%NL%".
       "                        push \@{\$out},[\$stdout,\$stderr]%NL%".
       "                     } elsif (\$cmd->[1]->[1] eq %NL%".
       "                           %SQ%docker_attach%SQ%) {%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->docker_attach(%NL%".
       "                           \$cmd->[1]->[2]);%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->cmd(%NL%".
       "                           %SQ%hostname%SQ%);%NL%".
       "                        push \@{\$out},[\$stdout,\$stderr]%NL%".
       "                     }  elsif (\$cmd->[1]->[1] eq%NL%".
       "                           %SQ%docker_exit%SQ%) {%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->docker_exit();%NL%".
       "                        (\$stdout,\$stderr)=\$handles->{%NL%".
       "                           \$cmd->[1]->[0]}->cmd(%NL%".
       "                           %SQ%hostname%SQ%);%NL%".
       "                        push \@{\$out},[\$stdout,\$stderr]%NL%".
       "                     }%NL%".
       "                  }%NL%".
       "               } elsif (\$cmd->[0] eq %SQ%connect_secure%SQ%) {%NL%".
       "                  my \$identityfile=\$cmd->[1]->{%NL%".
       "                     %SQ%identityfile%SQ%};%NL%".
       "                  my \$pwd=`pwd`;%NL%".
       "                  chomp(\$pwd);%NL%".
       "                  \$identityfile=\$pwd.%SQ%/%SQ%.\$identityfile if%NL%".
       "                     -1==index(\$identityfile,%SQ%/%SQ%);%NL%".
       "                  my (\$connect_label) = passgen(NWORDS => 1,%NL%".
       "                     NLETT => 8);%NL%".
       "                  my \$server={%NL%".
       "                     Label => \$connect_label,%NL%".
       "                     IP => \$cmd->[1]->{%SQ%ip%SQ%},%NL%".
       "                     Login => \$cmd->[1]->{%SQ%login%SQ%},%NL%".
       "                     IdentityFile => \$identityfile,%NL%".
       "                     NoRetry => \$cmd->[1]->{%SQ%noretry%SQ%}||%NL%".
       "                        %SQ%%SQ%%NL%".
       "                  };%NL%".
       "                  my \$error=%SQ%%SQ%;my \$stdout=%SQ%%SQ%;%NL%".
       "                  my \$stderr=%SQ%%SQ%;%NL%".
       "                  (\$handles->{\$connect_label},\$error)=%NL%".
       "                     connect_ssh(\$server);%NL%".
       "                  if (\$error) {%NL%".
       "                     \$stdout=%SQ%%SQ%;%NL%".
       "                     \$stderr=\$error;%NL%".
       "                  } else {%NL%".
       "                     \$stdout=\$connect_label%NL%".
       "                  }%NL%".
       "                  push \@{\$out},[\$stdout,\$stderr];%NL%".
       "               }%NL%".
       "            } else {%NL%".
       "               (\$stdout,\$stderr)=\$fullauto->cmd(\$cmd);%NL%".
       "               push \@{\$out},[\$stdout,\$stderr]%NL%".
       "            }%NL%".
       "         }%NL%".
       "         \$stdout=encode_json \$out;%NL%".
       "         zmq_msg_send(\$stdout,\$socket);%NL%".
       "      }%NL%".
       "      Time::HiRes::sleep (.000001);%NL%".
       "%NL%".
       "   }%NL%".
       "};%NL%".
       "%NL%".
       "my \$zeromq_broker=sub {%NL%".
       "%NL%".
       "   print \"LOADING BROKER\\n\";%NL%".
       "%NL%".
       "   my \$ctx = zmq_init();%NL%".
       "   my \$frontend = zmq_socket(\$ctx, ZMQ_ROUTER);%NL%".
       "   my \$backend  = zmq_socket(\$ctx, ZMQ_ROUTER);%NL%".
       "%NL%".
       "   my \$rv  = zmq_bind(\$frontend,FRONTEND_URL());%NL%".
       "   assert(\$rv == 0);%NL%".
       "%NL%".
       "   \$rv     = zmq_bind(\$backend,BACKEND_URL());%NL%".
       "   assert(\$rv == 0);%NL%".
       "%NL%".
       "   my \@workers;%NL%".
       "%NL%".
       "   my (\$w_addr,\$delim,\$c_addr,\$data);%NL%".
       "   my \$items = [%NL%".
       "%NL%".
       "         {%NL%".
       "            events      => ZMQ_POLLIN,%NL%".
       "            socket      => \$frontend,%NL%".
       "            callback    => sub {%NL%".
       "%NL%".
       "                if (-1<\$#workers) {%NL%".
       "%NL%".
       "                    print \"frontend…\\n\";%NL%".
       "%NL%".
       "                    my \$buf = zmq_msg_init();%NL%".
       "                    my \@msg=();%NL%".
       "                    if (zmq_msg_recv(\$buf,\$frontend)) {%NL%".
       "                       push \@msg, zmq_msg_data(\$buf);%NL%".
       "                       while (zmq_getsockopt(\$frontend,ZMQ_RCVMORE)) {%NL%".
       "                          zmq_msg_recv(\$buf,\$frontend);%NL%".
       "                          push \@msg, zmq_msg_data(\$buf);%NL%".
       "                       }%NL%".
       "                    }%NL%".
       "%NL%".
       "                    assert(\$#msg);%NL%".
       "%NL%".
       "                    assert(\$#workers < NBR_WORKERS());%NL%".
       "%NL%".
       "                    zmq_msg_send(pop(\@workers),\$backend,ZMQ_SNDMORE);%NL%".
       "                    zmq_msg_send(%SQ%%SQ%,\$backend,ZMQ_SNDMORE);%NL%".
       "                    zmq_msg_send(\$msg[0],\$backend,ZMQ_SNDMORE);%NL%".
       "                    zmq_msg_send(%SQ%%SQ%,\$backend,ZMQ_SNDMORE);%NL%".
       "                    zmq_msg_send(\$msg[2],\$backend,);%NL%".
       "%NL%".
       "                }%NL%".
       "            },%NL%".
       "         },%NL%".
       "         {%NL%".
       "            events      => ZMQ_POLLIN,%NL%".
       "            socket      => \$backend,%NL%".
       "            callback    => sub {%NL%".
       "%NL%".
       "                print \"backend…\\n\";%NL%".
       "%NL%".
       "                my \$buf = zmq_msg_init();%NL%".
       "                my \@msg=();%NL%".
       "                if (zmq_msg_recv(\$buf,\$backend)) {%NL%".
       "                   push \@msg, zmq_msg_data(\$buf);%NL%".
       "                   while (zmq_getsockopt(\$backend,ZMQ_RCVMORE)) {%NL%".
       "                      zmq_msg_recv(\$buf,\$backend);%NL%".
       "                      push \@msg, zmq_msg_data(\$buf);%NL%".
       "                   }%NL%".
       "                }%NL%".
       "%NL%".
       "                assert(\$#msg);%NL%".
       "%NL%".
       "                \$w_addr = \$msg[0];%NL%".
       "                push(\@workers,\$w_addr);%NL%".
       "%NL%".
       "                \$delim = \$msg[1];%NL%".
       "                assert(\$delim eq %SQ%%SQ%);%NL%".
       "%NL%".
       "                \$c_addr = \$msg[2];%NL%".
       "%NL%".
       "                if(\$c_addr ne READY()){%NL%".
       "                    \$delim = \$msg[3];%NL%".
       "                    assert (\$delim eq %SQ%%SQ%);%NL%".
       "%NL%".
       "                    \$data = \$msg[4];%NL%".
       "%NL%".
       "                    print %SQ%sending %SQ%.\$data.%SQ% to %SQ%.\$c_addr.\"\\n\";%NL%".
       "%NL%".
       "                    zmq_msg_send(\$c_addr,\$frontend,ZMQ_SNDMORE);%NL%".
       "                    zmq_msg_send(%SQ%%SQ%,\$frontend,ZMQ_SNDMORE);%NL%".
       "                    zmq_msg_send(\$data,\$frontend);%NL%".
       "%NL%".
       "                } else {%NL%".
       "                    print %SQ%worker checking in: %SQ%.\$w_addr.\"\\n\";%NL%".
       "                }%NL%".
       "            },%NL%".
       "         },%NL%".
       "   ];%NL%".
       "   while(1){%NL%".
       "      zmq_poll(\$items);%NL%".
       "      select undef,undef,undef,0.025;%NL%".
       "      if (getppid==1) {%NL%".
       "         `pgrep -P \$\$ | xargs kill -TERM`;%NL%".
       "          exit;%NL%".
       "      }%NL%".
       "   }%NL%".
       "%NL%".
       "};%NL%".
       "%NL%".
       "my \$Fork = new Parallel::Forker();%NL%".
       "\$Fork->schedule(run_on_start => \$zeromq_broker)->run()%NL%".
       "   if \$Fork->in_parent;%NL%".
       "setpgrp(0,0) unless \$Fork->in_parent;%NL%".
       "%NL%".
       "for (1..NBR_WORKERS()) {%NL%".
       "%NL%".
       "   my \$Fork = new Parallel::Forker();%NL%".
       "   #\$SIG{TERM} = sub { \$Fork->kill_tree_all(%SQ%TERM%SQ%) ".
       "if \$Fork && \$Fork->in_parent; die \"Quitting...\\n\"; };%NL%".
       "   \$Fork->schedule(run_on_start => \$fa_sub)->run()%NL%".
       "      if \$Fork->in_parent;%NL%".
       "   setpgrp(0,0) unless \$Fork->in_parent;%NL%".
       "%NL%".
       "}%NL%";
   ($stdout,$stderr)=$handle->cmd(
      "${sudo}sed -i \'/use Catalyst::ScriptRunner/i$ad\' ".
      "./script/fullautoapi_fastcgi.pl");
   ($stdout,$stderr)=$handle->cmd( # bash shell specific
      "${sudo}sed -i \'s/%NL%/\'\"`echo \\\\\\n`/g\" ".
      "./script/fullautoapi_fastcgi.pl");
   ($stdout,$stderr)=$handle->cmd("${sudo}sed -i \"s/%SQ%/\'/g\" ".
      "./script/fullautoapi_fastcgi.pl");
   ($stdout,$stderr)=$handle->cmd("${sudo}ldconfig");
   ($stdout,$stderr)=$handle->cmd('./script/set_admin_password.pl');
   $handle->{_cmd_handle}->print(
      "./script/fullautoapi_fastcgi.pl -l localhost:3003 &");
   $prompt=substr($handle->{_cmd_handle}->prompt(),1,-1);
   while (1) {
      my $output.=Net::FullAuto::FA_Core::fetch($handle);
      if ($output=~/^(.*?)$prompt.*$/s) {
         print $1 if defined $1;
         last;
      }
      print $output;
      if (-1<index $output,'| /end') {
         $output=Net::FullAuto::FA_Core::fetch($handle);
         print $output;
         last;
      }
   }
   sleep 15;
   print "\n   ACCESS FULLAUTO API MANAGEMENT DASHBOARD AT:\n\n",
         " https://$public_ip  -OR-  https://localhost\n";
   my $thanks=<<'END';

     ______                  _    ,
       / /              /   ' )  /        /
    --/ /_  __.  ____  /_    /  / __ . . /
   (_/ / /_(_/|_/ / <_/ <_  (__/_(_)(_/_'   For Trying
                             //

           _   _      _         _____      _ _    _         _
          | \ | | ___| |_      |  ___|   _| | |  / \  _   _| |_  |
          |  \| |/ _ \ __| o o | |_ | | | | | | / _ \| | | | __/ | \
          | |\  |  __/ |_  o o |  _|| |_| | | |/ ___ \ |_| | ||     |
          |_| \_|\___|\__|     |_|   \__,_|_|_/_/   \_\__,_|\__\___/ (C)


   Copyright (C) 2000-2016  Brian M. Kelly  Brian.Kelly@FullAuto.com

END
   eval {
      local $SIG{ALRM} = sub { die "alarm\n" }; # \n required
      alarm 15;
      print $thanks;
      print "   \n   Press Any Key to EXIT ... ";
      <STDIN>;
   };alarm(0);
   print "\n\n\n   Please wait at least a minute for the Default Browser\n",
         "   to start with your new Catalyst installation!\n\n\n";
   &Net::FullAuto::FA_Core::cleanup;

};

my $standup_fullautoapi=sub {

   my $catalyst="]T[{select_fullautoapi_setup}";
   my $cnt=0;
   $configure_fullautoapi->($catalyst);
   return '{choose_demo_setup}<';

};

my $fullautoapi_setup_summary=sub {

   package fullautoapi_setup_summary;
   use JSON::XS;
   my $region="]T[{awsregions}";
   $region=~s/^"//;
   $region=~s/"$//;
   my $type="]T[{select_type}";
   $type=~s/^"//;
   $type=~s/"$//;
   my $money=$type;
   $money=~s/^.*-> \$(.*?) +(?:[(].+[)] )*\s*per hour$/$1/;
   $type=substr($type,0,(index $type,' ->')-3);
   my $catalyst="]T[{select_fullautoapi_setup}";
   $catalyst=~s/^"//;
   $catalyst=~s/"$//;
   print "REGION=$region and TYPE=$type\n";
   print "CATALYST=$catalyst\n";
   my $num_of_servers=0;
   my $ol=$catalyst;
   $ol=~s/^.*(\d+)\sServer.*$/$1/;
   if ($ol==1) {
      $main::aws->{'CatalystFramework.org'}->[0]=[];
   } elsif ($ol=~/^\d+$/ && $ol) {
      foreach my $n (0..$ol) {
         $main::aws->{'CatalystFramework.org'}=[] unless exists
            $main::aws->{'CatalystFramework.org'};
         $main::aws->{'CatalystFramework.org'}->[$n]=[];
      }
   }
   $num_of_servers=$ol;
   my $cost=int($num_of_servers)*$money;
   my $cents='';
   if ($cost=~/^0\./) {
      $cents=$cost;
      $cents=~s/^0\.//;
      if (length $cents>2) {
         $cents=~s/^(..)(.*)$/$1.$2/;
         $cents=~s/^0//;
         $cents=' ('.$cents.' cents)';
      } else {
         $cents=' ('.$cents.' cents)';
      }
   }
   my $show_cost_banner=<<'END';

      _                  _       ___        _  ___
     /_\  __ __ ___ _ __| |_    / __|___ __| ||__ \
    / _ \/ _/ _/ -_) '_ \  _|  | (__/ _ (_-<  _|/_/
   /_/ \_\__\__\___| .__/\__|   \___\___/__/\__(_)
                   |_|

END
   $show_cost_banner.=<<END;
   Note: There is a \$$cost per hour cost$cents to launch $num_of_servers
         AWS EC2 $type servers for the FullAuto Demo:

         $catalyst


END
   my %show_cost=(

      Name => 'show_cost',
      Item_1 => {

         Text => "I accept the \$$cost$cents per hour cost",
         Result => $standup_fullautoapi,

      },
      Item_2 => {

         Text => "Return to Choose Demo Menu",
         Result => sub { return '{choose_demo_setup}<' },

      },
      Item_3 => {

         Text => "Exit FullAuto",
         Result => sub { Net::FullAuto::FA_Core::cleanup() },

      },
      Scroll => 1,
      Banner => $show_cost_banner,

   );
   return \%show_cost;

};

our $select_fullautoapi_setup=sub {

   my @options=('FullAuto Automation API on 1 Server');
   my $fullautoapi_setup_banner=<<'END';
                     _    ___     _ _   _       _                     
                   ((_)  | __|  _| | | /_\ _  _| |_  |                   
                    /    | _| || | | |/ _ \ || |  _/ | \   Automates     _
                   /     |_| \_,_|_|_/_/ \_\_,_|\__\___/c  Everything  _| |_ 
               \__/_     ___ __ _| |_ __ _| |_   _ ___| |_            |_   _|
               /    \   / __/ _` | __/ _` | | | | / __| __|  Perl MVC   |_|
            _- |    |  | (_| (_| | || (_| | | |_| \__ \ |    framework
       _ _-'   \____/   \___\__,_|\__\__,_|_|\__, |___/\__|c
     ((_)       ---\                         |___/
                    \
                     \\_   Web Framework & Automation API via RESTful
                      (_)

   Choose the FullAutoAPI setup you wish to demo. Note that more servers
   means more expense, and more instances means less permformance on a
   small instance type. Consider a medium or large instance type (previous
   screens) if you wish to test more than 1 instance on a server. You can
   navigate backwards and make new selections with the [<] LEFTARROW key.

END
   my %select_fullautoapi_setup=(

      Name => 'select_fullautoapi_setup',
      Item_1 => {

         Text => ']C[',
         Convey => \@options,
         Result => $standup_fullautoapi,

      },
      Scroll => 1,
      Banner => $fullautoapi_setup_banner,
   );
   return \%select_fullautoapi_setup

};

1