From e9c13ae06e13bec5475c0009a39e2cddaf5e58ed Mon Sep 17 00:00:00 2001 From: Will Budic Date: Thu, 15 May 2025 18:22:04 +1000 Subject: [PATCH 1/1] init --- apps/PageHTMLPlugin.pm | 201 ++++++++++++++++++++++++ apps/PageletArticlePlugin.pm | 106 +++++++++++++ apps/PerlCNFWebServerBase.pm | 44 ++++++ apps/app.cnf | 285 +++++++++++++++++++++++++++++++++++ apps/app.html | 34 +++++ apps/app_defaults.cnf | 5 + apps/index_markup.cgi | 113 ++++++++++++++ apps/index_markup.cnf | 63 ++++++++ apps/index_markup.html | 110 ++++++++++++++ apps/main.html | 138 +++++++++++++++++ apps/manifest.json | 21 +++ 11 files changed, 1120 insertions(+) create mode 100755 apps/PageHTMLPlugin.pm create mode 100755 apps/PageletArticlePlugin.pm create mode 100644 apps/PerlCNFWebServerBase.pm create mode 100644 apps/app.cnf create mode 100644 apps/app.html create mode 100644 apps/app_defaults.cnf create mode 100755 apps/index_markup.cgi create mode 100644 apps/index_markup.cnf create mode 100644 apps/index_markup.html create mode 100644 apps/main.html create mode 100644 apps/manifest.json diff --git a/apps/PageHTMLPlugin.pm b/apps/PageHTMLPlugin.pm new file mode 100755 index 0000000..d33d5e3 --- /dev/null +++ b/apps/PageHTMLPlugin.pm @@ -0,0 +1,201 @@ + +package PageHTMLPlugin; +use lib::relative '.'; +use PerlCNFWebServerBase; + + + +our %TEMPLATES; + +sub new { bless {params=>{}}, shift } + +sub loadTemplate ($self, $parser, $path) { + if(-e $path){ + if(not exists $TEMPLATES{$path}){ + my $template = CNFGlobalFile -> new($path); + my %props = %{$parser->collections()}; + $TEMPLATES{$path} = \$template; + $props{templates} = \%TEMPLATES; + $self -> {content} = $template -> content(); + $parser -> log("Loaded template: $path") + }else{ + my $template = $TEMPLATES{$path}; + if($$template -> changed()){ + $self -> {content} = $$template -> content(); + $parser -> log("Reloaded changed template: $path") + }else{ + $self -> {content} = $$template -> {content}; + $parser -> log("Using cached template: $path") + } + } + return 1 + }else{ + PageHTMLPluginException->throw(error=>"Template not found:$path", show_trace=>1) + } +} + +### +# If (cgi) parameters are set the Pagelet value has to be reprocessed. +### +sub setParameters ($self, $parser, $prp, $params){ + if(defined $params){ + my %parameters; + foreach (keys %$params){ + $parameters{$_} = $params->{$_} + } + $self -> {parameters} = %parameters; + process ($self, $parser, $prp) + } +} + +sub resolvePropVal($parser, $property){ + my $ref = ref($property); + if($ref eq 'Pagelet'){ + return $property->{html_body} + } + elsif($ref eq 'PropertyValueStyle'){ + if(exists $property->{plugin}) { + my $plugin = $property->{plugin}; + if(ref($$plugin) eq 'PageHTMLPlugin'){ + return $$plugin -> {content} if exists $$plugin -> {content} + } + # What ever this is in the CNF repository as a plugin other than this. + # Convention is to store in value field. + return $$plugin -> {value} + } + } + return $parser->{$property} if exists $parser->{$property}; + return $parser -> anon($property) +} + +sub process ($self, $parser, $prp) { my ($config, $meta); + try{ + my $app_tree = 'App'; + my $property = $parser -> property($prp); + $property = $prp if not $property; + if (exists $self -> {parameters}) { + $property = $property -> {cnf_property}; + $app_tree = $self -> {parameters} -> {app} if $self -> {parameters} -> {app} + } + if (my $val = resolvePropVal($parser, $property)) { + $val = $$val if ref($val) eq 'SCALAR'; + if ($config = $parser->anon($app_tree)) { + if ( $meta = $config->node('header/meta') ) { + foreach my $node (@{$meta->list()}) { + if ( $node->{data} ) { + $val = dataPropertyToHTMLParagraphs($parser->data()->{$node->{data}}); + } else { + $val = processNodeWithProperty($parser, $node, $val ); + } + } + my @template = ($val =~ m/^(.*)\s* + *\s* + (.*) + <\![-]+\s*PerlCNF\s*Template\s*End\s*[-]+>*\s*(.*)/mxsi); + $val = $template[1]; + $parser->collections()->{$prp} = \Pagelet ->new({plugin => $self , + property => $prp, + subroutine => 'process', + cnf_property => $parser -> property($prp), + html_head => \$template[0], + html_body => \$val, + html_foot => \$template[2], + }); + return 1; + } + else {die "Where is meta node in [$app_tree] property?"} + } + else {die "Where is the [$app_tree] property?"} + } + else {die "Unable to resolve CNF property -> $prp"} + }catch($e){ + PageHTMLPluginException->throw(error=>$e, show_trace=>1) + } +} + +sub processNodeWithProperty($parser, $node, $val) { + my ($tag,$rep); + my @nodes = $node->nodes(); + if(@nodes){ + foreach my $sub(@nodes){ + my $bf; + foreach($sub->nodes()){ + $bf .= "<".$_->name(); + foreach($_->attributes()){ + my @pair = @$_; + $bf .= qq( $pair[0] = "$pair[1]"); + } + $bf .= ">\n"; + } + $tag ='<\![-]+\s*<@<\s*' . $sub->name() . '\s*>@>\s*[-]+>'; + if(!$bf){ + $rep = qq([\$\$\$[ ). $sub->name() .' is UNDEFINED in subnodes! ]$$$]'; + $val =~ s/$tag/$rep/xg if defined $rep; + }else{ + $val =~ s/$tag/$bf/xg; + } + } + return $val; + }elsif($node->{property} ){ + $rep = $node->{property} + }else{ + $rep = $node->val() + } + + $tag = '<\![-]+\s*<@<\s*' . $node -> {tag} . '\s*>@>\s*[-]+>'; + if(!$rep){ + $rep = '[$$$[ '. $node -> {tag} .' is UNDEFINED! ]$$$]'; + }else{ + my $ref = ref($rep); + if($ref eq 'SCALAR'){ + $rep = $$rep + }elsif($ref eq 'PropertyValueStyle'){ + my $value = $rep -> {value}; + if(!$value){ + $rep = ${$parser -> data() -> {$rep->{property}}} + }else{ + $rep = $value; + } + }elsif($ref eq "Pagelet"){ + $rep = $rep -> {html_body}; + }elsif($ref ne ''){ + $rep = $rep -> val() + } + } + + $val = $$val if ref($val) eq 'SCALAR'; + $rep =~ s/^\s*|\s*$//gs; + + $rep = $node->{title} . $rep if $node->{title}; + $rep = $node->{head} . $rep if $node->{head}; + $rep .= $node->{foot} if $node->{foot}; + + $val =~ s/$tag/$rep/xg; + + return $val; +} + +sub dataPropertyToHTMLParagraphs($data_struct) { + my $ret = ""; + foreach my $record (@{$$data_struct->{data}}) { + + my $p = qq(
+

@$record[1]

+

@$record[2]

+
); + $ret .= $p ."\n"; + + } + return $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/apps/PageletArticlePlugin.pm b/apps/PageletArticlePlugin.pm new file mode 100755 index 0000000..6576455 --- /dev/null +++ b/apps/PageletArticlePlugin.pm @@ -0,0 +1,106 @@ +package PageletArticlePlugin; +use PluginBase; + + sub new { bless {params=>{}}, shift } + + sub resolvePropVal($parser, $property){ + my $ref = ref($property); + if($ref eq 'Pagelet'){ + return $property->{html_body} + } + elsif($ref eq 'PropertyValueStyle'){ + if(exists $property->{plugin}) { + my $plugin = $property->{plugin}; + if(ref($$plugin) eq 'PageHTMLPlugin'){ + return $$plugin -> {content} if exists $$plugin -> {content} + } + # What ever this is in the CNF repository as a plugin other than this. + # Convention is to store in value field. + return $$plugin -> {value} + } + } + return $parser->{$property} if exists $parser->{$property}; + return $parser -> anon($property) + } + + sub publish ($self, $parser, $prp_name) { + my ($cnf_property, $buffer); + if($prp_name =~ m/(\w*)\*$/){ + $prp_name = $1; + my @list = $parser->list($prp_name); + foreach my $ins(@list){ + $cnf_property = $parser -> anon($ins->{ele}.$ins->{aid}); + $buffer .= $self->publish_item ($parser, $cnf_property); + } + }else{ + $cnf_property = resolvePropVal($parser, $prp_name); + $buffer = $self->publish_item ($parser, $cnf_property); + } + $parser->collections()->{$prp_name} = \ Pagelet -> new ({plugin => $self , + property => $prp_name, + subroutine => 'process', + cnf_property => $cnf_property, + html_body => $buffer, + }) ; + return 1; + } + + sub publish_item ($self, $parser, $item) { + try{ + my $result; + my $ref = ref($item); + if($ref eq 'CNFNode'){ + foreach my $node($item->nodes()){ + if($node ->name() eq 'article'){ + my $nd_img = $node -> node('img'); + my $nd_txt = $node -> node('text'); + if($nd_img ne CNFNode::EMPTY()){ + + my $title = $nd_img->{title}; + my $alt = $nd_img->{alt}; + if($alt){ + $alt = 'alt="'. $alt . '"' + }else{ + $alt = 'alt' + } + $nd_txt = $nd_txt ->val(); + my $nd_url = $nd_img -> {url}; + my $nd_url_low = $nd_img -> {url_high}; + my $nd_url_high = $nd_img -> {url_low}; + my $nd_siz = $nd_img -> node('sizes'); + $nd_siz = "(min-width: 800px) 480px" if $nd_siz eq CNFNode::EMPTY(); + + + $result .= +qq(
+
+
$title
+ +
+
+ $nd_txt +
+
) + } + } + } + } + $result =~ s/^\s*//gs; + return $result + }catch($e){ + PageHTMLPluginException->throw(error=>$e, show_trace=>1) + } + } + + + +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/apps/PerlCNFWebServerBase.pm b/apps/PerlCNFWebServerBase.pm new file mode 100644 index 0000000..f0dd908 --- /dev/null +++ b/apps/PerlCNFWebServerBase.pm @@ -0,0 +1,44 @@ +package PerlCNFWebServerBase; +use v5.36; #For younger Perl rebases change only here version, and bellow line 23. And brace for warnings in logs. +use Syntax::Keyword::Try; no warnings qw(experimental::signatures); +use feature qw(signatures); +use Exception::Class ('PageHTMLPluginException'); +use Module::Load; + autoload CNFGlobalFile; + autoload CNFParser; + +package Pagelet { + + sub new($class, $args){ + return bless $args, $class; + } + + sub val($self){ + return $self -> {html_body} if exists $self -> {html_body} + } +} + + +sub import { + feature->import(':5.36'); + feature->import('signatures'); + warnings->import; + strict->import; + Module::Load->import; + Syntax::Keyword::Try->import; + Exception::Class->import('PageHTMLPluginException'); + CNFGlobalFile->import; + + my $caller = caller(0); + do { + no strict 'refs'; + *{"$caller\:\:Pagelet"} = *{Pagelet}; + *{"$caller\:\:isTrue"} = *{CNFParser::_isTrue}; + }; + + +} + + + +1; \ No newline at end of file diff --git a/apps/app.cnf b/apps/app.cnf new file mode 100644 index 0000000..993c91b --- /dev/null +++ b/apps/app.cnf @@ -0,0 +1,285 @@ +!CNF3.3 + +<<>> +<<>> +< + Please <@< meta_1 >@>, this line is a paragraph. + <@< dynamic_paragraphs >@> +>> +### +# In CNF Nodes shorthand format assigned are all template substitutions here. +# The geeky shortifes are faster then normal CNF node tags, and use less recursion. +## +<__IN_SHORTIFE__ __PRIORITY_8__ +header __\ +<##> +meta __\ + @@ __\ + tag: page_title + Document Viewer App + __/ + @@ __\ + header __\ + link __| + rel = manifest + href = manifest.json + __~ + __/ + link __| + rel = stylesheet + href = ../web_sources/root.css + __~ + __/ + link __| + rel = stylesheet + href = ../web_sources/app.css + __~ + __/ + __/ + __/ + @@__\ + tag: css_style + property: <**> + __/ + @@__\ + tag: css_style_articles + property: <**> + __/ + @@__\ + tag : col_left + title: Document Viewer App + head:
Back To Main Page

+ property: <**> + foot:
+ __/ + @@__\ + tag : col_main + property: <**> + __/ + @@__\ + tag : col_right + <#< Test 2 >#> + __/ +__/ +>> + +< __PRIORITY_7___ + package : PageHTMLPlugin + subroutine : loadTemplate + property : apps/app.html +>> + +<< Processor __PRIORITY_9__ + package : PageHTMLPlugin + subroutine : process + property : PAGE_CONTENT +>> + +<< [$$$[ some_web_site_1 ]$$$] + +If not stays in macro format, like this -> [$$$[ This link doesn't exist ]$$$] + +## Second Chapter + +[$$$[MarkupInstructions]$$$] + +## Third Chapter + +[$$$[ArticleSample]$$$] + +>>> + +<< MarkupDocument __PRIORITY_6__ + package : MarkdownPlugin + subroutine : convert + property : MD1 + instructions : MarkupInstructions +>> + +<< MarkupInstructions __PRIORITY_3_ + +[links[ + [some_web_site_1[ + desc : desc_website_1_desc.html + url : https://somewebsite.com + ]some_web_site_1] +]links] +[particulars[ + <@@< + tag: ArticleSample + >@@> +]particulars] +<#< + This property holds further instructions on what actions and data is returned to client. + Including atomic descriptions and links that can be text rich and more informative. + + So this whole script is both markup to render HTML and to prove configuration, to an web service app. + The page might render differently for other markup script processor if is read as an md file. + +### HTTP compression + + HTTP compression is a capability that can be built into web servers and web clients to improve transfer speed and bandwidth utilization.[1] + + HTTP data is compressed before it is sent from the server: compliant browsers will announce what methods are supported to the server before downloading the correct format; browsers that do not support compliant compression method will download uncompressed data. The most common compression schemes include gzip and Brotli; a full list of available schemes is maintained by the IANA.[2] + + There are two different ways compression can be done in HTTP. At a lower level, a Transfer-Encoding header field may indicate the payload of an HTTP message is compressed. At a higher level, a Content-Encoding header field may indicate that a resource being transferred, cached, or otherwise referenced is compressed. Compression using Content-Encoding is more widely supported than Transfer-Encoding, and some browsers do not advertise support for Transfer-Encoding compression to avoid triggering bugs in servers.[3] + +>#> + +>> + + + +<PROPERTY>> +< + + + +.article{ + display: grid; + grid-template-columns: .5fr 1fr; + column-gap: 1px; + border: 1px solid rgb(133, 133, 233); + background-color: rgba(0, 0, 0, 0); + margin-bottom: 5px; +} +.img{ + display: grid; + grid-template-columns: 1fr; + padding: 5px; + # border: solid black 1px; + min-width: min-content; + + .title{ + text-align: left; + font-kerning: auto; + font-weight: bolder; + font-size: x-large; + padding-bottom: 5px; + } + img{ + max-width:380px; + } +} +.text{ + font-size: 20px; + padding-top: 20px; + text-align: left; + p{ + font-size: x-large; + } +} + +@layer base { + + @media (width > 599px) { + + .content>*:nth-child(1) { + flex: 1 2 0; + margin-left: .2rem; + } + + .content>*:nth-child(2) { + flex: 0 1 80%; + text-align: justify; + display: inline-block; + overflow: scroll; + border-radius: 10px; + } + + .content>*:nth-child(3) { + flex: 1 2 0; + margin-left: .2rem; + display: none; + } + } + + + + @media (width > 1440px) { + + .content>*:nth-child(1) { + flex: 1 2 .1%; + margin-left: .5rem; + } + .content>*:nth-child(2) { + flex: 0 1 90%; + margin-left: .1rem; + } + .content>*:nth-child(3) { + flex: 1 2 18%; + margin-left: .5rem; + display: none; + } + } + + } + +>> + + +< __IN_SHORTIFE__ __PRIORITY_2__ +article __\ + img __\ + title: Cat Deva + alt: Cat Diva Artistic Image + url: images/cat_deva_2.jpeg + url_high: images/cat_deva_2.jpeg 480w + url_low: images/cat_deva_2-240.jpeg 240w + sizes: 380px + + __/ + text __\ +

This is a beautiful picture.

__~ + __/ +__/ +>> +< __IN_SHORTIFE__ __PRIORITY_2__ +article __\ + img __\ + title: Cica + alt: Cica + url: images/cica_1.jpeg + url_high: images/cica_1.jpeg 480w + url_low: images/cica_1_240x240.jpeg 240w + sizes: 380px + + __/ + text __\ +

This is a beautiful picture two.

__~ + __/ +__/ +>> + + +< __IN_SHORTIFE__ __PRIORITY_2__ +article __\ + img __\ + title: Flowers In Spring + alt: Flowers Picture + url: images/flowers_1.jpeg + url_high: images/flowers_1.jpeg 480w + url_low: images/flowers_1_450x250.jpeg 450w + sizes: 480px + + __/ + text __\ +

This is a beautiful picture three.

__~ + __/ +__/ +>> + +<< ArticlePagelet __PRIORITY_5__ + package : PageletArticlePlugin + subroutine : publish + property : ArticleSample* +>> + diff --git a/apps/app.html b/apps/app.html new file mode 100644 index 0000000..e9b0a38 --- /dev/null +++ b/apps/app.html @@ -0,0 +1,34 @@ + + + + + + + + + <!--<@< page_title >@>--> + + + + + + + +
+ +
+ +
+ +
+ + + \ No newline at end of file diff --git a/apps/app_defaults.cnf b/apps/app_defaults.cnf new file mode 100644 index 0000000..578d484 --- /dev/null +++ b/apps/app_defaults.cnf @@ -0,0 +1,5 @@ +!CNF3.3 + +<<>> \ No newline at end of file diff --git a/apps/index_markup.cgi b/apps/index_markup.cgi new file mode 100755 index 0000000..2e8376f --- /dev/null +++ b/apps/index_markup.cgi @@ -0,0 +1,113 @@ +#!/usr/bin/env perl +# +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 "

Server Error

Error: $err
"; + } + set_message(\&handle_errors); +} + +use lib "/home/will/dev_new/LifeLog/htdocs/cgi-bin/system/modules"; +#use lib "system/modules"; +require CNFParser; require CNFNode; require CNFDateTime; + +exit &HTMLPageBuilderFromCNF; + +sub HTMLPageBuilderFromCNF { + + my $template = $0; $template =~ s/\.pl$|\.cgi$|\.perl/.html/g; + open( my $fh, "<:perlio", $template ) + or LifeLogException->throw("Can't open $template: $!"); + read $fh, my $content, -s $fh; + close $fh; + my $cnf = CNFParser::_configure ({ + DO_ENABLED => 1, HAS_EXTENSIONS => 1, ANONS_ARE_PUBLIC => 1, DEBUG => 1, + PAGE_CONTENT => \$content, + PAGE_HEAD => "", + PAGE_FOOT => "" + },$0); + my $ptr = $cnf->data(); + $ptr = $ptr->{'PAGE'}; + say $$ptr if $ptr; + return 0 +} + +use feature qw(signatures); +package PageHTMLPlugin { + sub new { bless {}, shift } + + sub resolvePropVal($parser,$prp){ + return exists $parser->{$prp} ? $parser->{$prp} : $parser -> anon($prp) + } + + sub process { + my ( $class, $parser, $prp, $config, $meta ) = @_; + if ( my $val = resolvePropVal($parser ,$prp) ) { + if ( $config = $parser->anon('App') ) { + if ( $meta = $config->node('meta') ) { + foreach my $node ( @{ $meta->list() } ) { + if ( $node->{data} ) { + $val = dataPropertyToHTMLParagraphs($parser->data()->{$node->{data}}); + } else { + # Notice DEBUG constance is not an app package required CNF default. + # Not declaring it init of an instance of parser, the following will fail. + # The{DEBUG=>1} is required, be set to 1 or 0. + print $node->toScript() if $parser->{DEBUG}; + $val = processNodeWithProperty( $node, $val ); + } + $parser->anon()->{$prp} = $val; + } + return 1; + } + else { die "Where is meta node in App property?" } + } + else { die "Where is App property?" } + } + else { die "Don't do that!" } + } + + + sub processNodeWithProperty( $node, $val ) { + my $tag = '<@<\s*' . $node->{tag} . '\s*>@>'; + my $rep = $node->{property} ? $node->{property} : $node->val(); + $rep =~ s/^\s*|\s*$//gs; + $val =~ s/$tag/$rep/xg; + return $val; + } + + sub dataPropertyToHTMLParagraphs($data_struct) { + my $ret = ""; + foreach my $record (@{$$data_struct->{data}}) { + + my $p = qq(
+

@$record[1]

+

@$record[2]

+
); + $ret .= $p ."\n"; + + } + return $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/apps/index_markup.cnf b/apps/index_markup.cnf new file mode 100644 index 0000000..a8bc55d --- /dev/null +++ b/apps/index_markup.cnf @@ -0,0 +1,63 @@ +!CNF3.3 + +< + Please <@< meta_1 >@>, this line is a paragraph. + + <@< dynamic_paragraphs >@> +>> +< +[meta[ + <@@< + tag : col_left + <#< Dear Visitor >#> + >@@> + <@@< + tag : col_main + property: <**> + >@@> + <@@< + tag : col_right + <#< Test 2 >#> + >@@> +]meta] +>> +<< Processor + package : main::PageHTMLPlugin + subroutine : process + property : PAGE_CONTENT +>> + +<<< Markup Document + +# Main Heading + + Introduction paragraph here. + +## First Chapter + +The story hear, etc, on and on. +If we have link CNF we macro as follow [$$$[ some_web_site_1 ]$$$] + +## Second Chapter +>>> + +<< MarkupInstructions + +[links[ + [some_web_site_1[ + provide : desc_website_1_desc.html + <##> + ]some_web_site_1] +]links] + +<#< + + This property holds further instructions on what actions and data is returned to client. + Including atomic descriptions and links that can be text rich and more informative. + + So this whole script is both markup to render HTML and to prove configuration, to an web service app. + The page might render differently for other markup script processor if is read as an md file. + +>#> + +>> \ No newline at end of file diff --git a/apps/index_markup.html b/apps/index_markup.html new file mode 100644 index 0000000..f94a722 --- /dev/null +++ b/apps/index_markup.html @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + +
+ +
+ +
    +
  • Item One
  • +
  • Item Two
  • +
+ +
+
+

+ MaryLou wore the tiara with real pride. + There was something that made doing anything she didn't really want to do a bit easier when she wore it. + She really didn't care what those staring through the window were thinking as she vacuumed her + apartment. +

Bljat

+

+
+
+ Test Right +
+
+ + + + \ No newline at end of file diff --git a/apps/main.html b/apps/main.html new file mode 100644 index 0000000..2f2a4d8 --- /dev/null +++ b/apps/main.html @@ -0,0 +1,138 @@ + + + + + + + + + <!--<@< page_title >@>--> + + + + + + + + + + +
+ +
+ +

Main

+

Main paragraph sample text.

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. + Facilis perferendis eius fuga dignissimos tempore repellendus aliquid eligendi iste, esse a quidem cum + totam deserunt + harum accusantium modi similique officiis? Nemo?

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Accusamus repudiandae, saepe, veritatis eveniet repellat qui ipsa quas possimus iure quae illo! Tenetur libero error dicta non illo, sint porro nihil?

+
+

Test

+
+

Lorem I

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, sint facere officia aliquid iste amet vel + iusto nulla tenetur error porro modi voluptatum reprehenderit! Maiores quidem debitis ex consequuntur + aspernatur?

+
+ +
+

Lorem II

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, sint facere officia aliquid iste amet vel + iusto nulla tenetur error porro modi voluptatum reprehenderit! Maiores quidem debitis ex consequuntur + aspernatur?

+ +

Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab similique quisquam distinctio ut nemo + culpa, esse fuga fugit eveniet sint, illum provident consequuntur expedita voluptate veritatis, tenetur quod + delectus error?

+
+ +
+

Lorem III

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Iure, sint facere officia aliquid iste amet vel + iusto nulla tenetur error porro modi voluptatum reprehenderit! Maiores quidem debitis ex consequuntur + aspernatur?

+ +

Lorem ipsum dolor sit amet consectetur adipisicing elit. Ab similique quisquam distinctio ut nemo + culpa, esse fuga fugit eveniet sint, illum provident consequuntur expedita voluptate veritatis, tenetur quod + delectus error?

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia + modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia + modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia + modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?

+

Lorem ipsum, dolor sit amet consectetur adipisicing elit. Fuga maiores eveniet quaerat maxime aspernatur mollitia + modi itaque dolore quis nihil! Hic facilis eum laborum ipsam fugiat reiciendis sunt odio ratione?

+ +
+
+ +
+

Test

+
+

Lorem II

+

Lorem ipsum dolor sit amet consectetur adipisicing elit. Repellat vero accusantium at illo accusamus molestiae + numquam eos optio odio quasi esse placeat eveniet, maxime deleniti vel earum mollitia rem quod?

+
+
+ + + + +
+ + +
+ + + + + \ No newline at end of file diff --git a/apps/manifest.json b/apps/manifest.json new file mode 100644 index 0000000..cc9af22 --- /dev/null +++ b/apps/manifest.json @@ -0,0 +1,21 @@ +{ + "short_name": "PerlCNFWEB", + "name": "PerlCNFWEBServer App", + "icons": [ + { + "src": "images/favicons/PerlCNFEagle_192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "images/favicons/PerlCNFEagle_512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" + } + \ No newline at end of file -- 2.34.1