# About Life Log
-* Life Log is an full database implementation, web journal of categorised logs and events in time.
+* Life Log is an full database implementation, web journal of categorized logs and events in time.
* It is meant to be limitless, fully searchable and viewed as mostly desired.
* Can be used and expanded, as it is also fully configurable.
+
+
-# L-Tags
-```HTML
- <<B<{Text To Bold}>>
+# LifeLog Post Tags
+```html
+<<B<{Text To Bold}>>
<<I<{Text To Italic}>>
-
<<TITLE<{Title Text}>>
-
<<LIST<{List of items delimited by new line to terminate item or with '~' otherwise.}>
-
<<IMG<{url to image}>>
-
<<FRM<{file name}_frm.png}>>
-```HTML
-
-*_frm.png images file pairs are located in the ./images folder of the cgi-bin directory.
-These are manually resized by the user. Next to the original. Otherwise considered as stand alone icons. *_frm.png Image resized to -> width="210" height="120"
-Example:
```
+* frm.png images file pairs are located in the ./images folder of the cgi-bin directory. These are manually resized by the user. Next to the original. Otherwise considered as stand alone icons.
+* _frm.png Image is resized to -> width="210" height="120"
+
+Examples:
+```html
+
../cgi-bin/images/
my_cat_simon_frm.png
my_cat_simon.jpg
- For log entry, place:
+ For log entry, place:
+ <<FRM<my_cat_simon_frm.png> <<TITLE<Simon The Cat>>
+ This is my pet, can you hold him for a week while I am on holiday?
+
+ Explicitly tag an URL in the log entry. Required if using in log IMG or FRM tags.
+ Otherwise link appears as plain text:
+ <<LNK<{url to image}>>
- <<FRM>my_cat_simon_frm.png> <<TITLE<Simon The Cat>>
- This is my pet, can you hold him for a week while I am on holiday?
```
-```HTML
-<<LNK<{url to image}>>
-```HTML
-Explicitly tag an URL in the log entry. Required if using in log IMG or FRM tags. Otherwise link appears as plain text.
\ No newline at end of file
+* YuoTube embed script is automatically parsed.
+
+Example:
+
+```pre
+
+<iframe width="560" height="315"
+src="https://www.youtube.com/embed/xxxxxx"
+title="YouTube video player" frameborder="0" allowfullscreen>
+</iframe>
+
+```
--- /dev/null
+# PerlCNF
+
+Perl based Configuration Network File Format Parser and Specifications.
+CNF file format supports used format extraction from any text file.
+Useful for templates and providing initial properties and values for an application settings.
+Has own textual data format. Therefore can also be useful for database data batch processing.
+
+This version doesn't parse the actual __DATA__ section of an perl file yet. Contact me if this is needed, and for any other possible, useful requests.
+It is at current v.2.6, and specification implemented.
+
+### [You can find the specification here](./Specifications_For_CNF_ReadMe.md).
+
+---
+
+NEWS (2022-11-18) - PerlCNF now provides custom test manager and test cases.
+That will in future be used for all projects as an copy from this project.
+This is all available in the ./test directory and is not a Perl module.
+
+---
+
+## Installation Of This Perl GitHub Project
+
+* Installation is standard.
+
+```sh
+ mkdir ~/dev; cd ~/dev
+ git clone https://github.com/wbudic/PerlCNF.git
+ cd PerlCNF
+```
+
+* To install required modules locally to home, do not run following with sudo in front.
+ * cd ~/dev/PerlCNF; #Perl tests and project directory is required to be the starting location.
+```sh
+ ./install_cpan_modules_required.pl
+```
+
+
+## Usage
+
+* Copy the system/modules/CNFParser.pm module into your project.
+* From your project you can modify and adopt, access it.
+* You can also make an perl bash script.
+
+```perl
+use lib "system/modules";
+use lib $ENV{'PWD'}.'/htdocs/cgi-bin/system/modules';
+require CNFParser;
+
+ my $cnf1 = new CNFParser('sample.cnf');
+ #Load config with enabled evaluation on the fly, of perl code embedded in config file.
+ my $cnf2 = new CNFParser('sample.cnf',{DO_enabled=>1, duplicates_overwrite=0});
+
+ ```
+## Sample CNF File
+
+```CNF
+<<<CONST
+$APP_NAME = "Test Application"
+$APP_VERSION = v.1.0
+>>>
+<<$APP_DESCRIPTION<CONST>
+This application presents just
+a nice multi-line template.
+>>
+
+<<@<@LIST_OF_COUNTRIES>
+Australia, USA, "Great Britain", 'Ireland', "Germany", Austria
+Spain, Serbia
+Russia
+Thailand, Greece
+>>>
+
+Note this text here, is like an comment, not affecting and simply ignored.
+<p>Other tags like this paragraph better put into a CNF property to be captured.</p>
+
+```
+
+```perl
+
+my $cnf = new CNFParser('sample.cnf');
+my @LIST_OF_COUNTRIES = @{$cnf -> collection('@LIST_OF_COUNTRIES')};
+print "[".join(',', sort @LIST_OF_COUNTRIES )."]";
+#prints -> [Australia,Austria,Germany,Great Britain,Greece,Ireland,Russia,Serbia,Spain,Thailand,USA]
+print "App Name: ".$cnf->constant('$APP_NAME')."]";
+#prints -> App Name: Test Application
+
+```
+
+## Run Test Cases
+
+* Tests are located in the projects **./test directory.
+* Example how to run them:
+
+ ```sh
+ perl ./tests/testAll.pl
+ ```
+
+* Check also the latest Perl CNF [example.cnf](./tests/example.cnf) scripted also as an tutorial.
+ * Yes! That is an actual valid configuration file.
+ * To only just run it or check use ``` perl ./tests/testExample.pl ```
--- /dev/null
+#!/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.
+#
+# Programed by: Will Budic
+# Open Source License -> https://choosealicense.com/licenses/isc/
+#
+use v5.30;
+use strict;
+use warnings;
+use Exception::Class ('LifeLogException');
+use Syntax::Keyword::Try;
+use DateTime;
+##
+# We is 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);
+}
+
+#debug ->
+use lib "/home/will/dev/LifeLog/htdocs/cgi-bin/system/modules";
+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 main();
+
+sub main {
+ my $html = obtainDirListingHTML('docs');
+ my $cnf = CNFParser->new(
+ $script_path."index.cnf",{
+ DO_enabled => 1,
+ ANONS_ARE_PUBLIC => 1,
+ PAGE_HEAD => "<h2>Index Page of Docs</h2>",
+ 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,"");
+ $ret .="<b>$dir →</b><ul>\n";
+ $ret .= listFiles($dir,$script_path);
+ my $handle;
+ opendir ($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){
+ $ret .= obtainDirListingHTML($dir.'/'.$node);
+ }
+ }
+ 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);
+ foreach my $file(@files){
+ if($file =~ /\.md$/){
+ my @title = getDocTitle($file);
+ $ret .= qq(\t\t\t<li><a href="$dir/$title[0]">$title[1]</a></li>\n);
+ }else{
+ ($file =~ m/(\w+\.\w*)$/g);
+ $ret .= qq(\t\t\t<li><a href="$dir/$1">$1</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)
+}
+
+
+
+
+
+
--- /dev/null
+!CNF2.8
+
+<<@<%HTTP_HEADER>
+-charset = UTF8
+-expires = +5s
+>>
+
+<<HEADER<TREE> _HAS_PROCESSING_PRIORITY_
+
+[JS[
+ [@@[wsrc/main.js]@@]
+ [@@[wsrc/jquery.js]@@]
+ [@@[wsrc/jquery-ui.js]@@]
+]JS]
+[CSS[
+ [@@[wsrc/main.css]@@]
+ [@@[wsrc/jquery-ui.css]@@]
+ [@@[wsrc/jquery-ui.theme.css]@@]
+ [@@[wsrc/jquery-ui.theme.css]@@]
+]CSS]
+
+<STYLE<
+[#[
+
+ #container{
+ border: 2px solid black;
+ width: 78%;
+ margin: 0 auto;
+ padding: 0px;
+ }
+
+ #header {
+ border: 1px solid gray;
+ background: rgba(128,128,128,0.2);
+ margin:5px;
+ }
+
+ #content {
+ border: 1px solid gray;
+ text-align: left;
+ vertical-align: middle;
+ margin:5px;
+ background: rgba(128,128,128,0.2);
+ }
+ #content ul {
+ padding-left: 20px;
+ }
+
+ #content a:hover {
+ color: #ff4d21;
+ font-weight: bolder;
+ background: rgba(255,255,255,0.2);
+ }
+
+ #footer {
+ border: 1px solid gray;
+ background: rgba(128,128,128,0.2);
+ margin:5px;
+ }
+
+ .span_status {
+ position: absolute;
+ top: 80px; left:420px;
+ border: 2px solid #94cde7;
+ padding: 5px;
+ text-align: center;
+ background: #ccffff;
+ text-decoration-style: wavy;
+ }
+ .md_doc {
+ background: white;
+ border: 1px solid gray;
+ padding: 10px; margin: 5px;
+ text-align: left;
+ }
+
+ #doc_display p{
+ margin: 0 auto;
+ padding: 5px;
+ vertical-align: left;
+ text-align: left;
+ }
+
+ .bra {
+ color: maroon;
+ padding: 2px;
+ font-weight: bold;
+ }
+ .key {
+ color: green;
+ }
+ div .html {
+ border:1px solid lightgray;
+ background: rgba(255,255,255,0.2);
+ padding-left:5px;
+ text-align: left;
+ }
+ div .code {
+ border:1px solid lightgray;
+ background: rgba(255,255,255,0.2);
+ padding-left:5px;
+ font-family:monospace;
+ text-align: left;
+ }
+ ul {
+ margin: 0px;
+ padding: 10px;
+ padding-top:0px;
+ }
+ #content li {
+ padding: 0px;
+ margin-left:30px;
+ }
+ .pre {
+ border:1px solid black;
+ background: rgba(255,255,255,0.2);
+ padding:15px;
+ text-align: left;
+ }
+
+
+]#]
+>STYLE>
+
+<SCRIPT<
+[#[
+function onIndexBodyLoad(){
+ console.log("Initiated page.");
+ $("#status").html("Index page is ready!").show();
+ $("#status").fadeOut(2000);
+ $("#content a").click(
+ function(e){
+ e.preventDefault();
+ $("#status").html("Loading: " + e.target.href).show().fadeOut(1000);
+ $.post('index.cgi', {action:'load', doc:e.target.getAttribute('href')}, loadDocResult).fail(
+ function(response) {$('#doc_display').html("Service Error: "+response.status,response.responseText)}
+ );
+ }
+ );
+ onBodyLoadGeneric();
+}
+
+function loadDocResult(content){
+ $('#doc_display').html(content);
+}
+]#]
+>SCRIPT>
+>>
+
+###
+# 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>
+
+ <*<HEADER>*>
+
+ Title: Index Page
+ OnLoad : onIndexBodyLoad()
+
+ <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:content
+ <*<PAGE_CONTENT>*>
+ >div>
+ <div<
+ id:doc_display
+ class:md_doc
+ <*<INFO_MD>*>
+ >div>
+ >div>
+ <div<
+ id:footer
+ <*<PAGE_FOOT>*>
+ <span<⌋↑>span>
+ <a<
+ id:code
+ href:#top
+ title:Go to top of page.
+ <#<To Top Of Page>#>
+ >a>
+ <span<⌈>span>
+ >div>
+ >div>
+ <!<Page brought to you by HTMLIndexProcessorPlugin, from the PerlCNF project.>!>
+>>
+
+<<CNF_TO_HTML<PLUGIN>
+ package : HTMLIndexProcessorPlugin
+ subroutine : convert
+ property : PAGE
+>>
+
+<<INFO_MD<
+### INFO
+This Documentation listing for the [LifeLog](https://github.com/wbudic/LifeLog) Application.
+
+[Open Source License](https://choosealicense.com/licenses/isc/)
+>>>
+
+<<INFO_MD_TO_HTML<PLUGIN> _HAS_PROCESSING_PRIORITY_
+ package : MarkdownPlugin
+ subroutine : convert
+ property : INFO_MD
+>>
+
+
+
+
+
+