]> lifelog.hopto.org Git - PerlCNFWEBServer.git/commitdiff
init
authorWill Budic <redacted>
Thu, 15 May 2025 08:23:11 +0000 (18:23 +1000)
committerWill Budic <redacted>
Thu, 15 May 2025 08:23:11 +0000 (18:23 +1000)
index.cgi [new file with mode: 0755]
index.cnf [new file with mode: 0644]
install_cpan_modules_required.pl [new file with mode: 0755]

diff --git a/index.cgi b/index.cgi
new file mode 100755 (executable)
index 0000000..46a1fa7
--- /dev/null
+++ b/index.cgi
@@ -0,0 +1,116 @@
+#!/usr/bin/env perl
+# A delegated CNFParser processed rendering of the Document Index Web page, a Model-View-Controller Pattern approuch.
+# The index.cnf script contains the structure and page skeleton,
+# all configuration as well as the HTMLIndexProcessorPlugin converting the CNF to final HTML.
+# It is very convienient, as both style and script for the page is separated and developed in the index.cnf.
+# Which then can be moved to a respective include file over there.
+# This controller binds and provides to the parser to do its magic thing.
+#
+use v5.30;
+use strict;
+use warnings;
+use Exception::Class ('LifeLogException');
+use Syntax::Keyword::Try;
+##
+# We use dynamic perl compilations. The following ONLY HERE required to carp to browser on
+# system requirments or/and unexpected perl compiler errors.
+##
+use CGI::Carp qw(fatalsToBrowser set_message);
+
+BEGIN {
+   sub handle_errors {
+      my $err = shift;
+      say "<html><body><h2>Server Error</h2><pre>Error: $err</pre></body></html>";
+  }
+  set_message(\&handle_errors);
+}
+
+use lib "system/modules";
+require CNFParser;
+require CNFNode;
+
+our $GLOB_HTML_SERVE = "'{}/*.cgi' '{}/*.htm' '{}/*.html' '{}/*.md' '{}/*.txt'";
+our $script_path = $0; $script_path =~ s/\w+.cgi$//;
+
+exit &HTMLPageBuilderFromCNF;
+
+sub HTMLPageBuilderFromCNF {
+    my $html = obtainDirListingHTML('docs');
+    my $cnf  = CNFParser -> new (
+                            $script_path."index.cnf",{
+                             DO_ENABLED => 1, HAS_EXTENSIONS=>1,
+                             ANONS_ARE_PUBLIC => 1,
+                                PAGE_HEAD     => "<h1 id=\"index_head\">Index Page of Docs Directory</h1>",
+                                PAGE_CONTENT  => $html,
+                                PAGE_FOOT     => "<!--Not Defined-->"
+                            }
+                );
+    my $ptr = $cnf->data();
+    $ptr = $ptr->{'PAGE'};
+    say $$ptr if $ptr;
+    return 0
+}
+
+sub obtainDirListingHTML {
+    my ($dir, $ret) = (shift,"");
+    my $html = listFiles($dir,$script_path,"");
+    if($html){
+       $ret .="<ul><b>$dir &#8594;</b>\n";
+       $ret .= $html;
+        opendir (my $handle, $script_path.$dir) or die "Couldn't open directory, $!";
+        while (my $node = readdir $handle) {
+            my $file_full_path = "$script_path$dir/$node";
+            if($node !~ /^\./ && -d $file_full_path){
+               $html = obtainDirListingHTML($dir.'/'.$node);
+               $ret .= $html if $html
+            }
+        }
+        closedir $handle;
+       $ret .= "</ul>";
+    }
+    return $ret;
+}
+
+sub listFiles ($){
+    my ($dir, $script_path, $ret) = @_;
+    my $path = $script_path.$dir;
+    my $spec = $GLOB_HTML_SERVE; $spec =~ s/{}/$path/gp;
+    my @files = glob ($spec);
+       @files =  sort {
+            ( $a=~m/\w+[_-]*/ eq $b=~m/\w+[_-]*/ && length $a > length $b) ||
+              $a <=> $b
+    }  @files;
+    foreach my $file(@files){
+            ($file =~ m/(\w+\.\w*)$/g);
+            my $name = $1;
+            if($file =~ /\.md$/){
+                my @title = getDocTitle($file);
+                $ret .= qq(\t\t\t<li><a href="$dir/$title[0]">$title[1]</a> &dash; $name</li>\n);
+            }else{
+                $ret .= qq(\t\t\t<li><a href="$dir/$name">$name</a></li>\n);
+            }
+    }
+
+    return $ret;
+}
+
+sub getDocTitle($){
+    my ($file,$ret) = shift;
+    open(my $fh, '<', $file) or LifeLogException->throw("Can't open $file: $!");
+    while (my $line = <$fh>) {
+        if($line =~ /^#+\s*(.*)/){
+           $ret = $1;
+           last;
+        }
+    }
+    close $fh;
+    ($file =~ m/(\w+\.\w*)$/g);
+    return ($1,$ret)
+}
+1;
+=begin copyright
+Programed by  : Will Budić
+EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source        : https://github.com/wbudic/LifeLog
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright
diff --git a/index.cnf b/index.cnf
new file mode 100644 (file)
index 0000000..2f03cf0
--- /dev/null
+++ b/index.cnf
@@ -0,0 +1,575 @@
+!CNF3.3
+
+<<@<%WEBAPP_SETTINGS>
+    $LOG_PATH    = data
+    //TODO We are reading only the css property, old way is the following hash, preserved as reminder.
+    $THEME       = css => wsrc/main.css, colBG => #c8fff8, colSHDW => #9baec8
+>>
+
+
+<<@<%HTTP_HEADER>
+-charset =   "UTF8"
+-expires =   "+5s"
+>>
+
+<<CURRENT_THEME<PREPROCESS>
+    package     : PreProcessorObtainThemeSettings
+    subroutine  : process
+    property    : THEME
+>>
+
+<<HEADER<TREE> _HAS_PROCESSING_PRIORITY_
+
+[JS[
+    [@@[wsrc/main.js]@@]
+    [@@[wsrc/feeds.js]@@]
+    [@@[wsrc/jquery.js]@@]
+    [@@[wsrc/jquery-ui.js]@@]
+]JS]
+[CSS[    
+    [@@[wsrc/jquery-ui.css]@@]
+    [@@[wsrc/jquery-ui.theme.css]@@]
+    [@@[wsrc/jquery-ui.theme.css]@@]
+    [@@[wsrc/main.css]@@]
+    [@@[wsrc/effects.css]@@]
+    [@@[wsrc/feeds.css]@@]    
+]CSS]
+
+<STYLE<
+[#[
+    #container{
+        border: 2px solid #00000017;
+        width: 78%;
+        margin: 0 auto;
+        padding: 0px;
+    }
+
+    #header {
+        border: 1px solid gray;
+        background: rgba(0, 223, 246, 0.13);
+        margin:5px;
+    }
+
+    #content {
+        border: 1px solid gray;
+        border-top:0;
+        text-align: left !important;
+        vertical-align: middle;
+        /*margin:5px;*/
+        background: rgba(0, 223, 246, 0.13);
+    }
+    #tabspanels > div {
+        border: none;
+        text-align:left !important;
+        padding: 0;
+        border-width: 0;
+    }
+    .no-top-border {
+        border-top: none;
+    }
+    .textual {
+        width: 40%;
+    }
+    .textual p::first-letter {
+        color: blueviolet;
+        initial-letter: 3 2;
+        padding-right:  5pt;
+    }
+    #content ul {
+        background: transparent;
+        color:black;
+        margin: 0;
+        padding:5px;
+    }
+    #content li {
+        padding: 0px;
+        margin-left:30px;
+    }
+
+    #content li a:link {
+        font-weight: normal;
+        color:rgb(26, 96, 111);
+    }
+
+    #content li:hover {
+        color: #ff4d21;
+        font-weight: bolder;
+        background: rgba(255,255,255,0.2);
+    }
+
+    #content li a:visited {
+     color:  rgb(150, 8, 8);
+     font-weight: bold;
+    }
+
+
+    #footer {
+        border: 1px solid gray;
+        background: rgba(128,128,128,0.2);
+        margin:5px;
+    }
+
+
+    .md_doc {
+        background: white;
+        border: 1px solid gray;
+        border-top: 0;
+        padding: 10px; margin: 5px;
+        text-align: left;
+        overflow-y:scroll;
+        color:black;
+        margin:0 auto;
+    }
+
+    .md_doc ul{
+        font-size: large;
+    }
+
+    .md_doc p{
+        margin: 0 auto;
+        padding: 5px;
+        text-align: left;
+        font-weight: normal;
+    }
+
+    .md_doc blockquote  {
+        margin-top: 0;
+        margin-bottom: 16px;
+        background:#b2f8ef;
+        border-left: 3px solid #94cde7;
+        border-top:  2px solid #94cde7;
+        border-right:  2px solid #94cde7;
+    }
+    .md_doc blockquote  > :last-child{
+        border-bottom:  2px solid #94cde7;
+    }
+
+    .div_img{
+        height:450px;
+    }
+
+    .md_img{
+        height:80%;
+    }
+
+    code, pre{
+       font-family: 'Droid Sans Mono', 'monospace', monospace;
+    }
+
+    .pre {
+        border:1px solid black;
+        background: rgba(255,255,255,0.2);
+        padding:15px;
+        text-align: left;
+    }
+    .sh {
+        background: black;
+        color: lightgreen;
+        padding: 15px;
+        width: auto;
+        border-radius: .32em;
+        border: 2px solid lightgreen;
+        margin: inherit;
+        margin-right: 30px;
+    }
+
+    div .html {
+        border:1px solid lightgray;
+        background: rgba(255,255,255,0.2);
+        padding:10px;
+        font-family:monospace;
+        text-align: left;
+    }
+
+    div .cnf {
+        border:1px solid lightgray;
+        background: rgba(255,255,255,0.2);
+        padding:10px;
+        font-family:monospace;
+        text-align: left;
+        padding-bottom: 10px;
+        margin-right: 2px;
+        margin-top: 15px;
+    }
+
+    dt{
+        margin-right: 2px;
+    }
+
+    .cnf h1{
+        text-align: left;
+        padding-left: 15px;
+        margin-top: -20px;
+        height: 20px;
+        line-height: 20px;
+        font-size: 15px;
+    }
+
+    .cnf h1 span{
+        background-color: white;
+        border:1px solid lightgray;
+        color:lightgray;
+        font-size:small;
+        padding: 3px;
+        padding-left: 5px;
+        padding-right: 5px;
+    }
+
+
+    div .perl {
+        border:1px solid lightgray;
+        background:  rgba(149, 215, 172, 0.2);
+        padding-left:15px;
+        font-family:monospace;
+        text-align: left;
+        padding-bottom: 20px;
+        margin-right: 2px;
+        margin-top: 15px;
+    }
+
+    .mermaid{
+        border:1px solid lightgray;
+        background: transparent;
+        padding-left:15px;
+        text-align: left;
+        padding-bottom: 20px;
+        margin-right: 2px;
+        margin-top: 15px;
+    }
+
+    .perl h1{
+        text-align: left;
+        padding-left: 15px;
+        margin-top: -10px;
+        height: 20px;
+        line-height: 20px;
+        font-size: 15px;
+    }
+
+    .perl h1 span{
+        background:  rgba(170, 227, 191, 0.75);
+        border:1px solid lightgray;
+        color:black;
+        font-size:small;
+        padding: 3px;
+        padding-left: 5px;
+        padding-right: 5px;
+    }
+
+    .span_status {
+        position: absolute;
+        /* top: 80px;
+         left:420px;*/
+        border: 2px solid #94cde7;
+        padding: 5px;
+        text-align: center;
+        background: #ccffff;
+        text-decoration-style: wavy;
+        filter: drop-shadow(    10px 8px 5px #3e6f70);
+        z-index:10;
+    }
+
+    div#tabs  {
+        background:transparent;
+        border:0;
+        padding: 0;
+    }
+
+    div#tabs ul  {
+        background:transparent;
+    }
+
+    div#tabs li {
+        font-style: normal;
+        font-weight: bolder;
+        padding:1px;
+        border-top-left-radius:15px;
+        border-top-right-radius:15px;
+        border-bottom: 0;
+        margin-top: 0;
+
+    }
+
+
+    div#tabs .ui-tabs-anchor {
+        padding: .01em 1em;
+        color:black;
+    }
+    div#tabs ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header, .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover {
+    border: 1px solid #050506;
+    background: transparent;
+    font-style: normal;
+    font-weight: normal;
+    margin-top: 0px;
+    border-bottom: 0;
+    }
+
+    div#tabspanels .ui-state-active a {
+    color: #472f80;
+    text-decoration-line: underline;
+    }
+
+    #menu_page .menu_head a {
+        background: rgba(255,255,255,.6)
+    }
+    .span-content{
+            border: 1px solid black;
+            text-align: left;
+            background-color: #e6ffff;
+            vertical-align: top;
+    }
+
+]#]
+>STYLE>
+
+<STYLE<
+    <*<MarkdownPlugin::CSS>*>
+>STYLE>
+
+<SCRIPT<
+[#[
+var PREV_DIR_ELE = null;
+function onIndexBodyLoad(){
+    console.log("Initiated page.");
+    $("#status").html("Index page is ready!").show();
+    $("#status").fadeOut(2000);
+
+    selectIDAnchors();
+    $("#content a").prop("visitied",false);
+    onBodyLoadGeneric();
+
+    $( function() {
+        $( "#tabs" ).tabs();
+    });
+    $( "#tabs" ).show();
+}
+
+function loadDocResult(content){
+    $('#doc_display').html(content);
+    $("#status").fadeOut(2000);
+    $(document).scrollTop($("#content_pane").offset().top);
+    if(window.mermaid){
+       window.mermaid.run();
+    }
+    selectIDAnchors();
+    $('#tab_display').click();
+}
+
+function  selectIDAnchors(){
+   $("#content a").click(
+        function(e){
+            e.preventDefault();
+            $("#status").prependTo( $("#content_pane").parentElement );
+            $("#status").html("Loading: " + e.target.href).show();
+            $("#status").prependTo(e.target.parentElement);
+                if(PREV_DIR_ELE){
+                   PREV_DIR_ELE.parentElement.setAttribute("style","");
+                }
+            e.target.parentElement.setAttribute("style","color:  rgb(136, 58, 200); background-color: rgba(244, 241, 241, 0.386); font-size: large;  padding-left:1em;border-radius:15px; text-align:center;");
+            PREV_DIR_ELE = e.target;
+            $.post('index.cgi', {action:'load', doc:e.target.getAttribute('href')}, loadDocResult).fail(
+                    function(response) {$('#doc_display').html("Service Error: "+response.status,response.responseText)}
+            );
+        }
+    );
+}
+function gotoTabDirListing(){
+    $('#tab_dir_listing').click();
+}
+function gotoTabDisplay(){
+    $('#tab_display').click();
+}
+]#]
+>SCRIPT>
+
+
+
+>>HEADER>TREE>
+
+
+
+###
+# We in plugin mainly access this PAGE property, <*<HEADER>*> is linked in for clarity,
+# and/or if want to change from keeping the original \<\<HEADER<TREE>...\>\> above.
+#
+<<PAGE<TREE> __PROCESS_LAST__
+
+ <*<HEADER>*>
+
+ Title: Index Page
+ OnLoad : onIndexBodyLoad()
+
+<div<
+    id:menu_page
+ <#<
+    <span class="menu_head">
+        <a id="to_bottom" href="#bottom" title="Go to bottom of page.">
+        <span class="ui-icon ui-icon-arrowthick-1-s" style="float:none;"></span></a>
+               <span class="menu_title">&nbsp; Page &nbsp;</span>
+        <a id="to_top" href="#top" title="Go to top of page.">
+        <span class="ui-icon ui-icon-arrowthick-1-n" style="float:none;"></span></a>
+    </span>
+    <hr>
+    <a class="ui-button ui-corner-all ui-widget" href="app">App</a><br><br>
+    <a class="ui-button ui-corner-all ui-widget" href="index.cgi">Index</a><br><br>
+    <a class="ui-button ui-corner-all ui-widget" href="#htop" onclick="gotoTabDirListing()">&lt; Listing &gt;</a><br><br>
+    <a class="ui-button ui-corner-all ui-widget" href="#htop" onclick="gotoTabDisplay()">&lt; Display &gt;</a>
+    <hr>
+    <a class="ui-button ui-corner-all ui-widget" href="main.cgi">Life Log</a><hr>
+    <a class="ui-button ui-corner-all ui-widget" onclick="return fetchFeeds()">RSS Feeds</a>
+>#>
+ >div>
+<div<
+id:index-content
+class:content
+style:"height:100vh"
+ <div<
+    id:container
+        <div<
+            id:header
+        <*<PAGE_HEAD>*>
+                                                    <a<
+                                                        name: top
+                                                    >a>
+        >div>
+        <div<
+             id:content_pane
+            <span<
+              id:status
+              class:span_status
+              <#<Page getting ready...>#>
+            >span>
+
+            <div<
+            id="tabs"
+            style="height:auto;display:none;"
+                <ul<
+                <#<
+                    <li><a id="tab_dir_listing" href="#listing" selected>Directory Listing</a></li>
+                    <li><a id="tab_display" href="#display">Display</a></li>
+                >#>
+                >ul>
+                <div<
+                    id="tabspanels"
+                    class:no-top-border
+                        <div<
+                            id="listing"
+                            class="no-top-border"
+                            <div<
+                            id="content"
+                            <*<PAGE_CONTENT>*>
+                            >div>
+                        >div>
+                        <div<
+                            id="display"
+                            class="ui-state-active no-top-border league-mono-thin-condensed-tnum"
+                            <div<
+                                    id:doc_display
+                                    class:md_doc
+                                    <*<EMPTY_TAB_INFO>*>
+                            >div>
+                        >div>
+                        <script<
+                         type="module"
+                            <#<
+                            import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.esm.min.mjs';
+                            mermaid.initialize({
+                            securityLevel: 'loose',
+                            });
+                            window.mermaid = mermaid;
+                            >#>
+                        >script>
+                >div>
+            >div>
+
+
+            <div<
+            id:doc_display_bottom
+            class:md_doc
+                <*<INFO_MD>*>
+            >div>
+                                        <a<
+                                                        name="feed_top"
+                                        >a>
+            <a<
+                id: rss_anchor
+            >a>
+            <div<
+                id="feeds"
+                class="rz"
+                style ="margin: 5px; visibility:hidden"
+                [#[ RSS Here ]#]
+            >div>
+        >div>
+        <div<
+            id:footer
+            <*<PAGE_FOOT>*>
+            <span<&#8968;>span>
+                        <a<
+                            href:#top
+                            title:Goto top of page.
+                            onClick: gotoTabDirListing()
+                            <#<Show Dir Listing>#>
+                        >a>
+
+            <span<&#8971;&nbsp;&#8968;>span>
+                        <a<
+                            id:code
+                            href:#top
+                            title:Go to top of page.
+                            <#<To Top Of Page>#>
+                        >a>
+
+
+            <span<&#8971;>span>
+                                                        <a<
+                                                            name: bottom
+                                                        >a>
+        >div>
+ >div>
+    <!<Page brought to you by HTMLIndexProcessorPlugin, from the PerlCNF project.>!>
+>div>
+>>
+
+<<EMPTY_TAB_INFO<ESCAPED>
+### Tab is currently empty!
+\>Please, select a link from the [directory listing](#top|onclick="gotoTabDirListing()") above.**
+\<pre class="mermaid"\>graph TD;
+CNF&lt;--&gt;Application
+Application--&gt;Database
+Application--&gt;WebService
+WebService&lt;--&gt;CNF
+WebService&lt;--&gt;Database
+Database &lt;--&gt; CNF
+\</pre\>
+>>
+
+<<INFO_MD<ESCAPED> _HAS_PROCESSING_PRIORITY_
+
+### INFO
+\> This Page is the Documentation listing coming with the [LifeLog](https://github.com/wbudic/LifeLog) Application.
+\>
+\>[Open Source License](https://choosealicense.com/licenses/isc/)
+
+<h3>CHANGE3</h3>
+<center>Page brought to you by HTMLIndexProcessorPlugin v.<*<HTMLIndexProcessorPlugin::VERSION>*> in Moon Stage (beta).</center>
+
+>>
+
+<<CNF_TO_HTML<PLUGIN> __PROCESS_LAST__
+    package     : HTMLIndexProcessorPlugin
+    subroutine  : convert
+    property    : PAGE
+>>
+
+<<INFO_MD_TO_HTML<PLUGIN> _HAS_PROCESSING_PRIORITY_
+    package     : MarkdownPlugin
+    subroutine  : convert
+    property    : INFO_MD
+>>
+<<INFO_MD_TO_HTM2L<PLUGIN> _HAS_PROCESSING_PRIORITY_
+    package     : MarkdownPlugin
+    subroutine  : convert
+    property    : EMPTY_TAB_INFO
+>>
+<<1>>
diff --git a/install_cpan_modules_required.pl b/install_cpan_modules_required.pl
new file mode 100755 (executable)
index 0000000..c573912
--- /dev/null
@@ -0,0 +1,220 @@
+#!/usr/bin/env perl
+##
+# Module installer for projects.
+# Run this script from any Project directory containing perl modules or scripts.
+##
+use warnings; use strict;
+###
+# Prerequisites for this script itself. Run first:
+# cpan Term::ReadKey;
+# cpan Term::ANSIColor;
+## no critic (ProhibitStringyEval)  
+use Term::ReadKey;
+use Term::ANSIColor qw(:constants);
+
+use constant PERL_FILES_GLOB => "*local/*.pl local/*.pm system/modules/*.pm tests/*.pm tests/*.pl *.pl *.pm *.cgi";
+
+my $project = `pwd`."/".$0; $project =~ s/\/.*.pl$//g;  $project =~ s/\s$//g;
+my @user_glob;
+our $PERL_VERSION = $^V->{'original'}; my $ERR = 0; my $key;
+
+print WHITE "\n *** Project Perl Module Installer coded by ",BRIGHT_RED, "https://github.com/wbudic", WHITE,"***", qq(
+         \nRunning scan on project path:$project 
+         \nYou have Perl on $^O [$^X] version: $PERL_VERSION\n
+);
+print BLUE "<<@<\@INC<\n# Your default module package paths:\n", YELLOW; 
+local $. = 0; foreach(@INC){  
+  print $.++.".: $_\n"; 
+}
+print BLUE ">>\n", RESET;
+if($> > 0){
+  print "You are NOT installing system wide, which is required for webservers CGI.\nAre you sure about this?\n"
+}else{
+  print "You are INSTALLING modules SYSTEM WIDE, are you sure about this?\n"
+}
+if(@ARGV==0){
+  print qq(\nThis program will try to figure out now all the modules 
+  required for this project, and install them if missing.
+  This can take some time.
+  ); 
+  print RED "Do you want to proceed (press either the 'Y'es or 'N'o key)?", RESET;
+
+do{
+  ReadMode('cbreak');  
+  $key = ReadKey(0); print "\n";
+  ReadMode('normal');
+    exit 1 if(uc $key eq 'N');
+    $key = "[ENTER]" if $key =~ /\n/;
+    print "You have pressed the '$key' key, that is nice, but why?\nOnly the CTRL+C/Y/N keys do something normal." if uc $key ne 'Y';
+  }while(uc $key ne 'Y');
+}
+else{
+  foreach(@ARGV){
+    if(-d $_){
+      $_ =~ s/\s$//g;
+      print "\nGlobing for perl files in $project/$_";
+      my @located = glob("$_/*.pl $_/*.pm");
+      print " ... found ".@located." files.";
+      push @user_glob, @located;
+      
+    }else{
+      warn "Argument: $_ is not a local directory."
+    }
+  }
+}
+
+my @locals=(); 
+print "\nGlobing for perl modules in project $project";
+my @perl_files = glob(PERL_FILES_GLOB); 
+print " ... found ".@perl_files." files.\n";
+push @perl_files, @user_glob;
+my %modules; my %localPackages;
+foreach my $file(@perl_files){
+   next if $0 =~ /$file$/;
+   if($file =~ /(\w*)\.pm$/){
+      $localPackages{$1}=$file;
+   }
+   print "\nExamining:$file\n";      
+   my $res  =  `perl -ne '/\\s*(^use\\s([a-zA-Z:]*))\\W/ and print "\$2;"' $file`;
+   my @list = split(/;+/,$res);
+   foreach(@list){
+     if($_=~ /^\w\d\.\d+.*/){
+      print "\tA specified 'use $_' found in ->$file\n";
+      if($PERL_VERSION ne $_){         
+         $_ =~s/^v//g;
+         my @fv = split(/\./, $_);
+         $PERL_VERSION =~s/^v//g;
+         my @pv = split(/\./, $PERL_VERSION);
+         push @fv, 0 if @fv < 3;
+         for my$i(0..$#fv){
+           if( $pv[$i] < $fv[$i] ){
+              $ERR++; print "\n\t\033[31mERROR -> Perl required version has been found not matching.\033[0m\n";
+              last
+           }
+         }
+      }
+     }
+   }
+   foreach(@list){    
+    $_ =~ s/^\s*|\s*use\s*//g;
+    $_ =~ s/[\'\"].*[\'\"]$//g;    
+    next if !$_ or $_ =~ /^[a-z]|\d*\.\d*$|^\W/;
+    $_ =~ s/\(\)|\(.*\)|qw\(.*\)//g;
+    $modules{$_}=$file if $_;
+    print "$_\n";
+   }
+   if($file=~/\.pm$/){# it is presumed local package module.  
+      $locals[@locals] = `perl -ne '/\\s*(^package\\s(\\w+))/ and print "\$2" and exit' $file`;
+   }
+}
+
+print WHITE "\nList of Modules required for thie project:\n";
+my @missing=(); 
+foreach my $mod (sort keys %modules){
+    my $missing;
+    eval "use $mod";
+    if ($@){
+      $missing[@missing] = $mod;
+      print MAGENTA "\t$mod \t in ", $modules{$mod}," is suspicious?\n";
+    }else{
+      print BLUE "\t$mod\n" 
+    }
+}foreach(@missing){
+  if(exists $localPackages{$_}){
+      delete $modules{$_}
+  }else{
+      print BRIGHT_RED $_, MAGENTA, " is missing!\n"
+  }
+}
+my %skip_candidates;
+my $missing_count = @missing;
+if($missing_count>0){
+  foreach my $candidate(@missing){
+    foreach(@locals){
+      if($_ eq $candidate && not exists $skip_candidates{$_}){
+        $missing_count--;        
+        $skip_candidates{$_} = 1;
+        print GREEN, "Found the missing $candidate module in locals.\n"
+      }
+    }
+  }
+}
+my $perls = `whereis perl`;
+print GREEN, "Following is all of ",$perls;
+print YELLOW, "Reminder -> Make sure you switched to the right brew release.\n" if $perls =~ /perlbrew/; 
+print RESET, "Number of local modules:",scalar(@locals),"\n";
+print RESET, "Number of external modules:",scalar(keys %modules),"\n";
+print RESET, "Number of cpan modules about to be tried to install:",$missing_count,"\n";
+
+print GREEN, qq(
+Do you still want to continue to compile/test/install or check further modules?
+Only the first run is the depest and can take a long time, i.e. if you have to install over 5 modules.
+At other times this will only check further your current status.
+
+Now (press either the 'Y'es or 'N'o key) please?), RESET;
+do{
+ReadMode('cbreak');  
+$key = ReadKey(0); print "\n";
+ReadMode('normal');
+  exit 1 if(uc $key eq 'N');
+  $key = "[ENTER]" if $key =~ /\n/;
+  print "You have pressed the '$key' key, that is nice, but why?\nOnly the CTRL+C/Y/N keys do something normal.\n" if uc $key ne 'Y';
+}while(uc $key ne 'Y');
+
+my ($mcnt,$mins) = (0,0);
+my @kangaroos = sort keys %skip_candidates;
+
+##
+# Some modules if found to be needed to be forcefeed. can be hardcoded here my friends, why not?
+##
+foreach ((                
+                'LWP::Simple',
+                'LWP::Protocol::https',
+                'XML::LibXML::SAX'
+)){
+  $modules{$_}=1; print "Forcefeed: $_\n"
+}
+
+MODULES_LOOP: 
+foreach my $mod (sort keys %modules){
+
+  foreach(@kangaroos){
+      if($_ eq $mod){
+        next MODULES_LOOP
+      }
+  }
+  $mcnt++;
+  ## no critic (ProhibitStringyEval)
+  eval "use $mod";
+  if ($@) {
+      system(qq(perl -MCPAN -e 'install $mod'));     
+      if ($? == -1) {
+        print "failed to install: $mod\n";
+      }else{  
+        my $v = eval "\$$mod\::VERSION";
+           $v = $v ? "(v$v)" : "";
+        print "Installed module $mod $v!\n";
+        $mins++
+      }    
+  }else{       
+   $mod =~ s/\s*$//;   
+   my $v = eval "\$$mod\::VERSION";
+      $v = $v ? "(v$v)" : "";
+      print "Skipping module $mod $v, already installed!\n";
+  }
+}
+print "\nProject $project\nRequires $mcnt modules.\nInstalled New: $mins\n";
+print "WARNING! - This project requires in ($ERR) parts code that might not be compatible yet with your installed/running version of perl (v$PERL_VERSION).\n" 
+if $ERR;
+
+
+=begin copyright
+Programed by  : Will Budic
+EContactHash  : 990MWWLWM8C2MI8K (https://github.com/wbudic/EContactHash.md)
+Source        : https://github.com/wbudic/PerlCNF.git
+Documentation : Specifications_For_CNF_ReadMe.md
+    This source file is copied and usually placed in a local directory, outside of its repository project.
+    So it could not be the actual or current version, can vary or has been modiefied for what ever purpose in another project.
+    Please leave source of origin in this file for future references.
+Open Source Code License -> https://github.com/wbudic/PerlCNF/blob/master/ISC_License.md
+=cut copyright