Google WiFi Mesh LAN Subnet Google Home Tutorial

Google WiFi Mesh LAN Subnet Google Home Tutorial

Google WiFi Mesh LAN Subnet Google Home Tutorial

Since the Google WiFi Mesh Networking Primer Tutorial‘s talk about Google Wifi Mesh networks, well, we stopped worrying about it, we’re guessing, because the product is really good.

Recently though, we’ve got it back into our thinking, not that we pretend to have great expertise on the intricacies of home WiFi networks, just an interest in them serving the purpose of providing speedy and timely connectivity. This new home networking setup involved …

… which begs the questions (for us)

What are the benefits of a LAN connected Google WiFi Mesh subnetwork?
Why does Google Wifi have 2 Ethernet ports?
What is the difference between WAN and LAN ports on Google WiFi?
What can Google Home help setup on a home network?

The end result of this setup was we see two WiFi broadband based networks on our list of networks we can connect to, and the network appears to perform better, as you’d be wanting to be the case.


Previous relevant Google WiFi Mesh Networking Primer Tutorial is shown below.

Google WiFi Mesh Networking Primer Tutorial

Google WiFi Mesh Networking Primer Tutorial

Do you remember when we discussed WiFi mesh networks when we presented Mesh Networking Primer Tutorial? Well, we changed our in-house WiFi arrangements (from the use of a WiFi Router Extender, when we presented Home Network Wireless Wi-Fi Router Extender Tutorial) here at RJM Programming, thanks team. We’ve installed a Google WiFi mesh network we’ve noticed has improved all of …

  • Extended range of good connections around the building
  • Faster response time on the net
  • Faster download and upload test results (you can test for yourself at the Google WiFi mobile app, as required)

We hasten to add here, this did not involve changes to NBN (here in Australia), and so nothing getting to the building has changed, and the NBN router at the top of the building remains as the conduit to the internet. That, quite patently, is not the end of the story regarding getting an overall good result with your online connection speed and productivity. You can improve the in-house network design in multiples of efficiency, we can certainly state after a day of non-buffering and no dropouts on Netflix and Stan in any room of the building. It costs, of course, but hardware is rarely free, and the installation support from Google is excellent, and the Google WiFi “meshers” are kind of cute, even cuter than Godzilla’s nemeses wouldn’t you say?!


Previous relevant Mesh Networking Primer Tutorial is shown below.

Mesh Networking Primer Tutorial

Mesh Networking Primer Tutorial

Here, in Australia, a lot of us are turning our attention to the impacts of the National Broadband Network we are currently undertaking. With this in mind, attention goes towards improving the internal WiFi systems of the residence in question.

And that is where the concept of “mesh networking” comes to the fore. Before we go on, though, we cannot pretend to know more than PC & Tech Authority’s April, 2018 edition’s “Mesh Networking … Your Questions Answered” shows and answers. There they road test the following “mesh networking” systems …

  • Asus Lyra
  • Devolo GigaGate
  • Google WiFi
  • Linksys Velop
  • Netgear Orbi
  • TP-Link Deco M5
  • Ubiquiti AmpliFi HD

… so will leave you to read their article to get those road test results. But this may be “jumping the gun” for many of us. Let’s define, all thanks to PC & Tech Authority’s April, 2018 edition’s “Mesh Networking … Your Questions Answered”

What is “mesh networking”?

“Mesh networking” has the same basic principle as wireless repeaters or extenders (which we have one of in our 9 room house, presently, and as you can read about at Home Network Wireless Wi-Fi Router Extender Tutorial) that sit in rooms a bit away from the router in the WiFi Wireless network within your residence. These wireless repeaters piggyback on the existing wireless network, but “mesh networking” use private radio channels (backhauls) to …

  • create better performance on public network
  • have less contention
  • not standalone like extenders, but form multiple nodes helped out by neighbours rather than needing that connection back to base … and so …
  • easier to extend over larger areas
How much is “mesh networking” going to cost me here in Australia?

Depending on how many nodes, say if it was 2-3 nodes, the price would probably be in the range A$200 to A$650.

Does a “mesh networking” replace existing routers?

Mostly, yes, but doesn’t have to if the router can be switched into modem mode or bridge mode. Obviously if “mesh network” is set up to replace an existing router then you need to have at hand that router’s admin username and password(s) before trying to reconfigure anything.

What coverage per node should you expect with most “mesh networking” systems?

Two or three nodes can often cover 400m2 but this is a bit determinant on the position of fridges and walls.

Are the speedier more expensive “mesh networking” systems overkill?

If an Internet connection of 40Mbits/sec suits your purposes, just about all the products will work for that. “Mesh networking”, though, could well be an investment for the future requirements.

Is it easy to set up “mesh networking”?

Most have a smartphone app to help. The “mesh networking” nodes often talk back to the smartphone app via bluetooth to help the setup also.

Want to do your research online? You could do worse than read Wikipedia’s Wireless Mesh Network webpage, thanks.

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Hardware, Installers, iOS, Networking, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

XML Lint Validation SelectionChange Tutorial

XML Lint Validation SelectionChange Tutorial

XML Lint Validation SelectionChange Tutorial

Onto yesterday’s XML Lint Validation Onclick Tutorial‘s …

  • left hand cell hosted pair of textarea element onclick (and ondblclick) event logics … today we think a user could benefit from …
  • right hand cell hosted textarea element SelectionChange (keyboard related) event triggered via the user highlighting that textarea text (containing errors) of interest

… via …

<?php echo ”

var thesel='', reng='';

function prereverseengineer() {
var wasreng=reng;
reng='';
reverseengineer(wasreng);
}

function reverseengineer(what) {
var oury2=0, nexty2=0;
var theheight=eval(eval('' + s2rect.height) / rowseq);
var codelines=s2.value.split(String.fromCharCode(10));
var errdetail='', ierr=0, linenum=0, nums=[];
thergb=redrgb;
var bimg='linear-gradient(to bottom, white, '; // ' white ' + y2 + 'px, ' + thergb + ' ' + y2 + 'px, ' + thergb + ' ' + eval(y2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s1rect.height) / rowseq) + 'px, white)';
var suff=', white)';

if (what.trim() != '') {
nums=what.split(',');
}
if (eval('' + nums.length) > 0) {
window.scrollTo(0,0);
s1.title='' + nums[0]; // + linenum;
s2.title='' + codelines[eval(-1 + eval('' + nums[0]))];
//alert(what);
oury2=eval(eval(-1 + eval('' + nums[0])) * theheight);
bimg+=' white ' + oury2 + 'px, ' + thergb + ' ' + oury2 + 'px, ' + thergb + ' ' + eval(oury2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(oury2 + eval('' + s1rect.height) / rowseq) + 'px, ';
for (ierr=1; ierr<nums.length; ierr++) {
oury2=eval(eval(-1 + eval('' + nums[ierr])) * theheight);
//bimg+=thergb + ' ' + eval(oury2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + oury2 + 'px, ' + thergb + ' ' + oury2 + 'px, '; // + thergb + ' ' + eval(oury2 + eval('' + s1rect.height) / rowseq) + 'px, ';
bimg+=' white ' + oury2 + 'px, ' + thergb + ' ' + oury2 + 'px, ' + thergb + ' ' + eval(oury2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(oury2 + eval('' + s1rect.height) / rowseq) + 'px, ';
s1.title+=String.fromCharCode(10) + '' + nums[ierr]; // + linenum;
s2.title+=String.fromCharCode(10) + '' + codelines[eval(-1 + eval('' + nums[ierr]))];
}
if (bimg.indexOf(suff) == -1) { bimg+=suff.substring(1); }
s1.style.backgroundImage='' + bimg;
s2.style.backgroundImage='' + bimg;
document.getElementById('outgoing').title='Highlighted to left are codelines ' + what + ' with errors';
}
}

function decorateleft() {
var jerr=0;
reng=''
if (ourdelim == ':') {
for (jerr=1; jerr<ourfindsare.length; jerr++) {
if (ourfindsare[jerr].trim() != '') {
if (ourfindsare[jerr].substring(0,1) >= '0' && ourfindsare[jerr].substring(0,1) <= '9') {
if (ourfindsare[jerr].slice(-1) >= '0' && ourfindsare[jerr].slice(-1) <= '9') {
if ((',' + reng + ',').indexOf(',' + ourfindsare[jerr].split(':')[0] + ',') == -1) {
if (reng == '') { reng=ourfindsare[jerr]; } else { reng+=',' + ourfindsare[jerr]; }
}
}
}
}
}
} else if (ourdelim.trim() != '') {
for (jerr=1; jerr<ourfindsare.length; jerr++) {
if (ourfindsare[jerr].split(':')[0].trim() != '') {
if (ourfindsare[jerr].split(':')[0].substring(0,1) >= '0' && ourfindsare[jerr].split(':')[0].substring(0,1) <= '9') {
if (ourfindsare[jerr].split(':')[0].slice(-1) >= '0' && ourfindsare[jerr].split(':')[0].slice(-1) <= '9') {
if ((',' + reng + ',').indexOf(',' + ourfindsare[jerr].split(':')[0] + ',') == -1) {
if (reng == '') { reng=ourfindsare[jerr].split(':')[0]; } else { reng+=',' + ourfindsare[jerr].split(':')[0]; }
}
}
}
}
}
}
if (reng != '') {
setTimeout(prereverseengineer, 9000); // reverseengineer(reng);
}
}

function handleSelection() { // thanks to https://stackoverflow.com/questions/46651479/reacting-to-selection-changes-in-an-html-textarea
const activeElement = document.activeElement;

// Make sure this is your textarea
//document.title=(('' + activeElement.id) + activeElement.outerHTML.substring(0,23));
if (activeElement && activeElement.outerHTML.indexOf('<textarea') == 0 && ('' + activeElement.id) == 'outgoing') {
const range = {
start: activeElement.selectionStart,
end: activeElement.selectionEnd
};
ourdelim=':';
ourfindsare=[];
thesel='';
// Do something with your range
if (eval('' + range.end) > eval('' + range.start)) {
thesel=(activeElement.value.substring(range.start).substring(0, eval(eval('' + range.end) - eval('' + range.start) )));
if (thesel.trim() != '' && thesel.indexOf(':') != -1) {
var floc=thesel.split(':')[0];
if (tfis != '') {
if (eval('' + floc.length) >= eval('' + tfis.length)) {
ourdelim=tfis + ':';
ourfindsare=thesel.split(ourdelim);
} else {
thesel=thesel.replace(':', tfis + ':');
ourdelim=tfis + ':';
ourfindsare=thesel.split(ourdelim);
}
} else {
ourfindsare=thesel.split(ourdelim);
}
decorateleft();
}
}
}
}

document.addEventListener('selectionchange', handleSelection);

“; ?>

… in our changed “fourth draft” xmllint_validation.php you might want to try for yourself.


Previous relevant XML Lint Validation Onclick Tutorial is shown below.

XML Lint Validation Onclick Tutorial

XML Lint Validation Onclick Tutorial

Onto yesterday’s XML Lint Validation Browsing Tutorial XML Lint Validation web application progress, today, we start to add some onclick and ondblclick event logic to those left hand table cell pair of textarea elements …

<?php echo ”

function gcbr() {
if (rowseq != '') {
s1rect=s1.getBoundingClientRect();
s1.onclick=function(event) { s1click(event); };
s1.ondblclick=function(event) { alert('Line ' + s1.title + s1.getAttribute('data-status') + ':' + String.fromCharCode(10) + s2.title); };
s2rect=s2.getBoundingClientRect();
s2.onclick=function(event) { s2click(event); };
s2.ondblclick=function(event) { alert('Line ' + s1.title + s1.getAttribute('data-status') + ':' + String.fromCharCode(10) + s2.title); };
}

if (('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'').trim() != '') {
if (document.getElementById('myhxfile').value == '') {
document.getElementById('myhxfile').placeholder=decodeURIComponent(('' + location.hash).replace(/^\#/g,''));
var tf=document.getElementById('outgoing').value;
var tfis=tf.split(':')[0];
if (tfis.trim() != '') {
while (tf.indexOf(tfis + ':') != -1) {
tf=tf.replace(tfis + ':', decodeURIComponent(('' + location.hash).replace(/^\#/g,'')) + ':');
}
document.getElementById('outgoing').value=tf;
}
}
}
}

“; ?>

… and though we usually do not associate onclick logic with textarea elements, today we’re preferring that to any alternate use of div element alternative because, today, for the first time, we’re making use of the “sharp” colour stops mentioned by linear-gradient(), thanks …

<?php echo ”

function s1click(e) {
var theheight=eval(eval('' + s1rect.height) / rowseq);
var codelines=s2.value.split(String.fromCharCode(10));
var errdetail='', ierr=0, linenum=0;
if (e.touches) {
if (e.touches[0].pageX) {
x1=(eval(e.touches[0].pageX + document.body.scrollLeft * 1) * 1);
y1=(eval(e.touches[0].pageY + eval(eval(e.touches[0].pageY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].pageY + document.body.scrollTop - s1rect.top) / theheight)));
} else {
x1=(eval(e.touches[0].clientX + document.body.scrollLeft * 1) * 1);
y1=(eval(e.touches[0].clientY + eval(eval(e.touches[0].clientY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].clientY + document.body.scrollTop - s1rect.top) / theheight)));
}
} else if (e.clientX || e.clientY) {
x1=(e.clientX + document.body.scrollLeft * 1);
y1=(e.clientY + eval(eval(e.clientY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.clientY + document.body.scrollTop - s1rect.top) / theheight)));
} else {
x1=(e.pageX + document.body.scrollLeft * 1);
y1=(e.pageY + eval(eval(e.pageY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.pageY + document.body.scrollTop - s1rect.top) / theheight)));
}
//alert('' + linenum + ' ' + y1 + '/' + document.body.scrollTop + ' ... ' + s1.scrollTop + ' ... ' + s1rect.top + '/' + s1rect.y + ' +++ ' + theheight);
var finds=document.getElementById('outgoing').value.split(':' + linenum + ':');
thergb=greenrgb;
s1.setAttribute('data-status', '');
if (eval('' + finds.length) > 1) {
for (ierr=1; ierr<finds.length; ierr++) {
errdetail+=String.fromCharCode(10) + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10))[eval(-1 + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10)).length)] + ':' + linenum + ':' + finds[eval(0 + ierr)].split(String.fromCharCode(10))[0];
}
errdetail+=String.fromCharCode(10);
thergb=redrgb;
s1.setAttribute('data-status', ' (has errors ... ' + errdetail + ' ... over to the right)');
}
s1.title='' + linenum;
s2.title='' + codelines[eval(-1 + linenum)];
y1-=eval('' + s1rect.top);
// linear-gradient(to right, yellow, yellow 20%, #009966 20%, #009966 80%, purple 80%, purple);
//alert('linear-gradient(to bottom, white, white ' + y1 + 'px, ' + thergb + ' ' + y1 + 'px, ' + thergb + ' ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white)');
s2.style.backgroundImage='linear-gradient(to bottom, white, white ' + y1 + 'px, ' + thergb + ' ' + y1 + 'px, ' + thergb + ' ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white)';
s1.style.backgroundImage='linear-gradient(to bottom, white, white ' + y1 + 'px, ' + thergb + ' ' + y1 + 'px, ' + thergb + ' ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white)';
}

function s2click(e) {
var theheight=eval(eval('' + s2rect.height) / rowseq);
var codelines=s2.value.split(String.fromCharCode(10));
var errdetail='', ierr=0, linenum=0;
if (e.touches) {
if (e.touches[0].pageX) {
x2=(eval(e.touches[0].pageX + document.body.scrollLeft * 1) * 1);
y2=(eval(e.touches[0].pageY + eval(eval(e.touches[0].pageY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].pageY + document.body.scrollTop - s2rect.top) / theheight)));
} else {
x2=(eval(e.touches[0].clientX + document.body.scrollLeft * 1) * 1);
y2=(eval(e.touches[0].clientY + eval(eval(e.touches[0].clientY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].clientY + document.body.scrollTop - s2rect.top) / theheight)));
}
} else if (e.clientX || e.clientY) {
x2=(e.clientX + document.body.scrollLeft * 1);
y2=(e.clientY + eval(eval(e.clientY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.clientY + document.body.scrollTop - s2rect.top) / theheight)));
} else {
x2=(e.pageX + document.body.scrollLeft * 1);
y2=(e.pageY + eval(eval(e.pageY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.pageY + document.body.scrollTop - s2rect.top) / theheight)));
}
var finds=document.getElementById('outgoing').value.split(':' + linenum + ':');
thergb=greenrgb;
s1.setAttribute('data-status', '');
if (eval('' + finds.length) > 1) {
for (ierr=1; ierr<finds.length; ierr++) {
errdetail+=String.fromCharCode(10) + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10))[eval(-1 + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10)).length)] + ':' + linenum + ':' + finds[eval(0 + ierr)].split(String.fromCharCode(10))[0];
}
errdetail+=String.fromCharCode(10);
thergb=redrgb;
s1.setAttribute('data-status', ' (has errors ... ' + errdetail + ' ... over to the right)');
}
s1.title='' + linenum;
s2.title='' + codelines[eval(-1 + linenum)];
y2-=eval('' + s2rect.top);
s2.style.backgroundImage='linear-gradient(to bottom, white, white ' + y2 + 'px, ' + thergb + ' ' + y2 + 'px, ' + thergb + ' ' + eval(y2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s1rect.height) / rowseq) + 'px, white)';
s1.style.backgroundImage='linear-gradient(to bottom, white, white ' + y2 + 'px, ' + thergb + ' ' + y2 + 'px, ' + thergb + ' ' + eval(y2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s1rect.height) / rowseq) + 'px, white)';
}

“; ?>

to be able to add colour coding to (the background of) HTML textarea elements.

Also, a hashtagging idea is implemented to aid with bringing over a browsed for file name into the “reporting mix” in our changed “third draft” xmllint_validation.php you might want to try for yourself.


Previous relevant XML Lint Validation Browsing Tutorial is shown below.

XML Lint Validation Browsing Tutorial

XML Lint Validation Browsing Tutorial

Yesterday’s XML Lint Validation Tutorial had us starting out on a discovery tour of XML Lint, yesterday …

  • starting with an HTML or XML URL of interest incoming data way … and today, we add onto that …
  • a local HTML or XMLfile browsing means of defining your input data into …

our changed “second draft” xmllint_validation.php you might want to try for yourself, helped out by a tweaked client_browsing.htm client side HTML and Javascript inhouse helper.

Again, we see, into another way to yesterday’s work, how useful is a textarea element, in that it can facilitate the way …

  • HTML and XML data can be input via populating the textarea innerHTML attribute … which flows through to a …
  • textarea value attribute value where any < is mapped to &lt; and > is mapped to &gt; … ready for …
  • an HTML form hosted textarea, given a filled in name attribute be able to share this data to that form’s action attributed value …
    <?php

    function ronecheck() {
    if (document.getElementById('result1').innerHTML != '') {
    document.getElementById('incoming').innerHTML=document.getElementById('result1').value;
    document.getElementById('result1').innerHTML='';
    document.getElementById('result1').value='';
    document.getElementById('myhxfile').name='xx';
    document.getElementById('mysub').click();
    }
    }

    ?>
    … (in our case being the same PHP) …
  • able to be processed by recall PHP interventional code …
    <?php

    $vsnone='none';
    $prefn='Please enter either HTML or XML file to validate ...';
    $pth='';
    $rn='' .rand(1,78477554);
    $results='';
    $precontents='';
    $contents='';
    $fn='';
    if (!isset($_GET['htmlfile']) && isset($_GET['content'])) {
    $_GET['htmlfile']=$_GET['content'];
    }
    if (!isset($_POST['htmlfile']) && isset($_POST['content'])) {
    $_POST['htmlfile']=$_POST['content'];
    }
    if (isset($_GET['htmlfile'])) {
    if (substr(trim(urldecode($_GET['htmlfile'])) . ' ', 0, 1) == '<') {
    $contents=trim(str_replace('+',' ',urldecode($_GET['htmlfile'])));
    if (strpos(strtolower(explode('>', $contents)[0]), 'html') !== false) {
    $fn='/tmp/html_' . $rn . '.html';
    } else if (strpos(strtolower(explode('>', $contents)[0]), 'xml') !== false) {
    $fn='/tmp/xml_' . $rn . '.xml';
    }
    file_put_contents($fn, $contents);
    } else {
    $fn=str_replace('+',' ',urldecode($_GET['htmlfile']));
    }
    if ($fn != '') {
    if (strpos($fn, 'localhost') !== false) {
    $rhs=explode('localhost' . explode('/', explode('localhost', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    $pth='/usr/bin/';
    } else if (strpos($fn, 'rjmprogramming.com.au') !== false) {
    $rhs=explode('rjmprogramming.com.au' . explode('/', explode('rjmprogramming.com.au', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    } else if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
    $pth='/usr/bin/';
    }
    }
    if (file_exists($fn)) {
    if ($contents == '') {
    $contents=file_get_contents($fn);
    }
    $prefn=$fn;
    $fn=realpath($fn);
    if (strpos(strtolower($fn), '.xml') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    } else if (strpos(strtolower($fn), '.htm') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --html --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    }
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    } else {
    $contents='';
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    }
    } else if (isset($_POST['htmlfile'])) {
    if (substr(trim(urldecode($_POST['htmlfile'])) . ' ', 0, 1) == '<') {
    $contents=trim(str_replace('+',' ',urldecode($_POST['htmlfile'])));
    if (strpos(strtolower(explode('>', $contents)[0]), 'html') !== false) {
    $fn='/tmp/html_' . $rn . '.html';
    } else if (strpos(strtolower(explode('>', $contents)[0]), 'xml') !== false) {
    $fn='/tmp/xml_' . $rn . '.xml';
    }
    file_put_contents($fn, $contents);
    } else {
    $fn=str_replace('+',' ',urldecode($_POST['htmlfile']));
    }
    if ($fn != '') {
    if (strpos($fn, 'localhost') !== false) {
    $rhs=explode('localhost' . explode('/', explode('localhost', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    $pth='/usr/bin/';
    } else if (strpos($fn, 'rjmprogramming.com.au') !== false) {
    $rhs=explode('rjmprogramming.com.au' . explode('/', explode('rjmprogramming.com.au', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    } else if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
    $pth='/usr/bin/';
    }
    }
    if (file_exists($fn)) {
    $prefn=$fn;
    if ($contents == '') {
    $contents=file_get_contents($fn);
    }
    $fn=realpath($fn);
    if (strpos(strtolower($fn), '.xml') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    } else if (strpos(strtolower($fn), '.htm') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --html --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    //file_put_contents('xxx.xxx', $results);
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    }
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    } else {
    $contents='';
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    }
    }
    if ($contents != '') {
    $lines=explode("\n", $contents);
    for ($ii=1; $ii<=sizeof($lines); $ii++) {
    $precontents.='' . $ii . "\n";
    }
    }

    ?>

Cute, huh?!


Previous relevant XML Lint Validation Tutorial is shown below.

XML Lint Validation Tutorial

XML Lint Validation Tutorial

Do you remember when we discussed the Sanitizer API, talked about at Sanitizer API Primer Tutorial, regarding it as a web application HTML (and more) validation tool?

Well, we’ve based a new “validator” of HTML or XML using the XML Lint web application on what we did then, but this code needing to be …

  • under the auspices of a serverside scenario … ie. PHP … for us … calling on …
  • underlying operating system call such as (for HTML qsall.htm incoming data file) …

    xmllint --html --valid --noout ./qsall.htm

    … via …
  • shell_exec

… there’s not much left of the original HTML and Javascript!

We had a fun time with HTML textarea elements and scrolling with the resultant “first draft” xmllint_validation.php you might want to try for yourself supplying an HTML or XML URL of intetest. Why, in particular? Well, it was the first time that we remember trying to make practically useful …

  • a table cell (ie. td element) (the left of two) hosted …
  • two textarea element arrangement whereby, ideally. they view …
    1. side by side
    2. if one is scrolled the two identically scroll the same amount … (document.body outerHTML) HTML …
      <?php echo ”

      <body onload="s1 = document.getElementById('preincoming'); s2 = document.getElementById('incoming'); s1.addEventListener('scroll', select_scroll_1, false); s2.addEventListener('scroll', select_scroll_2, false);" data-onload='onl();'>
      <h1>XML Lint Validation <!--button onclick='trythis();' title='Try your own'>Usage</button--></h1>
      <h3>RJM Programming - June, 2024</h3>
      <form action=./xmllint_validation.php method=POST target=_self>
      <table style=width:95%; border=5>
      <tr><th colspan=2 style=text-align:center;>XML Lint validation of <input style=width:70%; onblur="if (this.value.length > 0) { document.getElementById('mysub').click(); }" name=htmlfile id=myhxfile placeholder='Please enter either HTML or XML file to validate ...' value="<?php echo str_replace('>','>',str_replace('<','<',$prefn)); ?>"></input></th></tr>
      <tr><th>Data to validate</th><th>XML Lint results</th></tr>
      <tr><td style=vertical-align:top;><textarea style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap;text-align:right; id=preincoming><?php echo str_replace('>','>',str_replace('<','<',$precontents)); ?></textarea><textarea onblur="if (this.value.length > 0 && '<?echo $fn; ?>' == '') { document.getElementById('mysub').click(); }" style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap; name=content id=incoming><?php echo str_replace('>','>',str_replace('<','<',$contents)); ?></textarea></td><td style=vertical-align:top;><textarea id=outgoing><?php echo str_replace('>','>',str_replace('<','<',$results)); ?></textarea></td></tr>
      <tr><td></td><td><input type=submit id=mysub style=display:<?php echo $vsnone; ?> value=Validate></input></td></tr>
      </table>
      </form>
      </body>

      “; ?>
      … uses Javascript …
      <?php echo ”

      var s1=null, s2=null;

      // Thanks to https://stackoverflow.com/questions/7108270/scrolling-2-different-elements-in-same-time
      function select_scroll_1(e) { s2.scrollTop = s1.scrollTop; }
      function select_scroll_2(e) { s1.scrollTop = s2.scrollTop; }

      “; ?>
      … so that …
    3. the left hand textarea contains code line numbers right aligned … to sidle up next to …
    4. the right hand textarea contains the code (HTML or XML) being validated by xmllint

    … while …

  • the right hand table cell contains the xmllint validation (of HTML or XML) results

… had us, in practice, thanking our lucky stars that …

  1. textarea elements are resizeable
  2. you can simulate “some cockpit action” aligning them vertically … Jim?!


Previous relevant Sanitizer API Primer Tutorial is shown below.

Sanitizer API Primer Tutorial

Sanitizer API Primer Tutorial

Today we’re roadtesting the Sanitizer API

The HTML Sanitizer API allow developers to take untrusted strings of HTML and Document or DocumentFragment objects, and sanitize them for safe insertion into a document’s DOM.

… as another validation idea for HTML to add to our previous HTML Online Validation Tidy Errors Tutorial efforts.

Perhaps you’d like to try the “Usage” button of the proof of concept web application below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

XML Lint Validation Onclick Tutorial

XML Lint Validation Onclick Tutorial

XML Lint Validation Onclick Tutorial

Onto yesterday’s XML Lint Validation Browsing Tutorial XML Lint Validation web application progress, today, we start to add some onclick and ondblclick event logic to those left hand table cell pair of textarea elements …

<?php echo ”

function gcbr() {
if (rowseq != '') {
s1rect=s1.getBoundingClientRect();
s1.onclick=function(event) { s1click(event); };
s1.ondblclick=function(event) { alert('Line ' + s1.title + s1.getAttribute('data-status') + ':' + String.fromCharCode(10) + s2.title); };
s2rect=s2.getBoundingClientRect();
s2.onclick=function(event) { s2click(event); };
s2.ondblclick=function(event) { alert('Line ' + s1.title + s1.getAttribute('data-status') + ':' + String.fromCharCode(10) + s2.title); };
}

if (('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'').trim() != '') {
if (document.getElementById('myhxfile').value == '') {
document.getElementById('myhxfile').placeholder=decodeURIComponent(('' + location.hash).replace(/^\#/g,''));
var tf=document.getElementById('outgoing').value;
var tfis=tf.split(':')[0];
if (tfis.trim() != '') {
while (tf.indexOf(tfis + ':') != -1) {
tf=tf.replace(tfis + ':', decodeURIComponent(('' + location.hash).replace(/^\#/g,'')) + ':');
}
document.getElementById('outgoing').value=tf;
}
}
}
}

“; ?>

… and though we usually do not associate onclick logic with textarea elements, today we’re preferring that to any alternate use of div element alternative because, today, for the first time, we’re making use of the “sharp” colour stops mentioned by linear-gradient(), thanks …

<?php echo ”

function s1click(e) {
var theheight=eval(eval('' + s1rect.height) / rowseq);
var codelines=s2.value.split(String.fromCharCode(10));
var errdetail='', ierr=0, linenum=0;
if (e.touches) {
if (e.touches[0].pageX) {
x1=(eval(e.touches[0].pageX + document.body.scrollLeft * 1) * 1);
y1=(eval(e.touches[0].pageY + eval(eval(e.touches[0].pageY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].pageY + document.body.scrollTop - s1rect.top) / theheight)));
} else {
x1=(eval(e.touches[0].clientX + document.body.scrollLeft * 1) * 1);
y1=(eval(e.touches[0].clientY + eval(eval(e.touches[0].clientY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].clientY + document.body.scrollTop - s1rect.top) / theheight)));
}
} else if (e.clientX || e.clientY) {
x1=(e.clientX + document.body.scrollLeft * 1);
y1=(e.clientY + eval(eval(e.clientY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.clientY + document.body.scrollTop - s1rect.top) / theheight)));
} else {
x1=(e.pageX + document.body.scrollLeft * 1);
y1=(e.pageY + eval(eval(e.pageY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.pageY + document.body.scrollTop - s1rect.top) / theheight)));
}
//alert('' + linenum + ' ' + y1 + '/' + document.body.scrollTop + ' ... ' + s1.scrollTop + ' ... ' + s1rect.top + '/' + s1rect.y + ' +++ ' + theheight);
var finds=document.getElementById('outgoing').value.split(':' + linenum + ':');
thergb=greenrgb;
s1.setAttribute('data-status', '');
if (eval('' + finds.length) > 1) {
for (ierr=1; ierr<finds.length; ierr++) {
errdetail+=String.fromCharCode(10) + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10))[eval(-1 + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10)).length)] + ':' + linenum + ':' + finds[eval(0 + ierr)].split(String.fromCharCode(10))[0];
}
errdetail+=String.fromCharCode(10);
thergb=redrgb;
s1.setAttribute('data-status', ' (has errors ... ' + errdetail + ' ... over to the right)');
}
s1.title='' + linenum;
s2.title='' + codelines[eval(-1 + linenum)];
y1-=eval('' + s1rect.top);
// linear-gradient(to right, yellow, yellow 20%, #009966 20%, #009966 80%, purple 80%, purple);
//alert('linear-gradient(to bottom, white, white ' + y1 + 'px, ' + thergb + ' ' + y1 + 'px, ' + thergb + ' ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white)');
s2.style.backgroundImage='linear-gradient(to bottom, white, white ' + y1 + 'px, ' + thergb + ' ' + y1 + 'px, ' + thergb + ' ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white)';
s1.style.backgroundImage='linear-gradient(to bottom, white, white ' + y1 + 'px, ' + thergb + ' ' + y1 + 'px, ' + thergb + ' ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s2rect.height) / rowseq) + 'px, white)';
}

function s2click(e) {
var theheight=eval(eval('' + s2rect.height) / rowseq);
var codelines=s2.value.split(String.fromCharCode(10));
var errdetail='', ierr=0, linenum=0;
if (e.touches) {
if (e.touches[0].pageX) {
x2=(eval(e.touches[0].pageX + document.body.scrollLeft * 1) * 1);
y2=(eval(e.touches[0].pageY + eval(eval(e.touches[0].pageY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].pageY + document.body.scrollTop - s2rect.top) / theheight)));
} else {
x2=(eval(e.touches[0].clientX + document.body.scrollLeft * 1) * 1);
y2=(eval(e.touches[0].clientY + eval(eval(e.touches[0].clientY % theheight) - theheight) + document.body.scrollTop * 1) * 1);
linenum=Math.floor(eval(1 + eval(eval(e.touches[0].clientY + document.body.scrollTop - s2rect.top) / theheight)));
}
} else if (e.clientX || e.clientY) {
x2=(e.clientX + document.body.scrollLeft * 1);
y2=(e.clientY + eval(eval(e.clientY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.clientY + document.body.scrollTop - s2rect.top) / theheight)));
} else {
x2=(e.pageX + document.body.scrollLeft * 1);
y2=(e.pageY + eval(eval(e.pageY % theheight) - theheight) + document.body.scrollTop * 1);
linenum=Math.floor(eval(1 + eval(eval(e.pageY + document.body.scrollTop - s2rect.top) / theheight)));
}
var finds=document.getElementById('outgoing').value.split(':' + linenum + ':');
thergb=greenrgb;
s1.setAttribute('data-status', '');
if (eval('' + finds.length) > 1) {
for (ierr=1; ierr<finds.length; ierr++) {
errdetail+=String.fromCharCode(10) + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10))[eval(-1 + finds[eval(-1 + ierr)].split(':' + linenum + ':')[0].split(String.fromCharCode(10)).length)] + ':' + linenum + ':' + finds[eval(0 + ierr)].split(String.fromCharCode(10))[0];
}
errdetail+=String.fromCharCode(10);
thergb=redrgb;
s1.setAttribute('data-status', ' (has errors ... ' + errdetail + ' ... over to the right)');
}
s1.title='' + linenum;
s2.title='' + codelines[eval(-1 + linenum)];
y2-=eval('' + s2rect.top);
s2.style.backgroundImage='linear-gradient(to bottom, white, white ' + y2 + 'px, ' + thergb + ' ' + y2 + 'px, ' + thergb + ' ' + eval(y2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s1rect.height) / rowseq) + 'px, white)';
s1.style.backgroundImage='linear-gradient(to bottom, white, white ' + y2 + 'px, ' + thergb + ' ' + y2 + 'px, ' + thergb + ' ' + eval(y2 + eval('' + s1rect.height) / rowseq) + 'px, white ' + eval(y1 + eval('' + s1rect.height) / rowseq) + 'px, white)';
}

“; ?>

to be able to add colour coding to (the background of) HTML textarea elements.

Also, a hashtagging idea is implemented to aid with bringing over a browsed for file name into the “reporting mix” in our changed “third draft” xmllint_validation.php you might want to try for yourself.


Previous relevant XML Lint Validation Browsing Tutorial is shown below.

XML Lint Validation Browsing Tutorial

XML Lint Validation Browsing Tutorial

Yesterday’s XML Lint Validation Tutorial had us starting out on a discovery tour of XML Lint, yesterday …

  • starting with an HTML or XML URL of interest incoming data way … and today, we add onto that …
  • a local HTML or XMLfile browsing means of defining your input data into …

our changed “second draft” xmllint_validation.php you might want to try for yourself, helped out by a tweaked client_browsing.htm client side HTML and Javascript inhouse helper.

Again, we see, into another way to yesterday’s work, how useful is a textarea element, in that it can facilitate the way …

  • HTML and XML data can be input via populating the textarea innerHTML attribute … which flows through to a …
  • textarea value attribute value where any < is mapped to &lt; and > is mapped to &gt; … ready for …
  • an HTML form hosted textarea, given a filled in name attribute be able to share this data to that form’s action attributed value …
    <?php

    function ronecheck() {
    if (document.getElementById('result1').innerHTML != '') {
    document.getElementById('incoming').innerHTML=document.getElementById('result1').value;
    document.getElementById('result1').innerHTML='';
    document.getElementById('result1').value='';
    document.getElementById('myhxfile').name='xx';
    document.getElementById('mysub').click();
    }
    }

    ?>
    … (in our case being the same PHP) …
  • able to be processed by recall PHP interventional code …
    <?php

    $vsnone='none';
    $prefn='Please enter either HTML or XML file to validate ...';
    $pth='';
    $rn='' .rand(1,78477554);
    $results='';
    $precontents='';
    $contents='';
    $fn='';
    if (!isset($_GET['htmlfile']) && isset($_GET['content'])) {
    $_GET['htmlfile']=$_GET['content'];
    }
    if (!isset($_POST['htmlfile']) && isset($_POST['content'])) {
    $_POST['htmlfile']=$_POST['content'];
    }
    if (isset($_GET['htmlfile'])) {
    if (substr(trim(urldecode($_GET['htmlfile'])) . ' ', 0, 1) == '<') {
    $contents=trim(str_replace('+',' ',urldecode($_GET['htmlfile'])));
    if (strpos(strtolower(explode('>', $contents)[0]), 'html') !== false) {
    $fn='/tmp/html_' . $rn . '.html';
    } else if (strpos(strtolower(explode('>', $contents)[0]), 'xml') !== false) {
    $fn='/tmp/xml_' . $rn . '.xml';
    }
    file_put_contents($fn, $contents);
    } else {
    $fn=str_replace('+',' ',urldecode($_GET['htmlfile']));
    }
    if ($fn != '') {
    if (strpos($fn, 'localhost') !== false) {
    $rhs=explode('localhost' . explode('/', explode('localhost', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    $pth='/usr/bin/';
    } else if (strpos($fn, 'rjmprogramming.com.au') !== false) {
    $rhs=explode('rjmprogramming.com.au' . explode('/', explode('rjmprogramming.com.au', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    } else if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
    $pth='/usr/bin/';
    }
    }
    if (file_exists($fn)) {
    if ($contents == '') {
    $contents=file_get_contents($fn);
    }
    $prefn=$fn;
    $fn=realpath($fn);
    if (strpos(strtolower($fn), '.xml') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    } else if (strpos(strtolower($fn), '.htm') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --html --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    }
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    } else {
    $contents='';
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    }
    } else if (isset($_POST['htmlfile'])) {
    if (substr(trim(urldecode($_POST['htmlfile'])) . ' ', 0, 1) == '<') {
    $contents=trim(str_replace('+',' ',urldecode($_POST['htmlfile'])));
    if (strpos(strtolower(explode('>', $contents)[0]), 'html') !== false) {
    $fn='/tmp/html_' . $rn . '.html';
    } else if (strpos(strtolower(explode('>', $contents)[0]), 'xml') !== false) {
    $fn='/tmp/xml_' . $rn . '.xml';
    }
    file_put_contents($fn, $contents);
    } else {
    $fn=str_replace('+',' ',urldecode($_POST['htmlfile']));
    }
    if ($fn != '') {
    if (strpos($fn, 'localhost') !== false) {
    $rhs=explode('localhost' . explode('/', explode('localhost', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    $pth='/usr/bin/';
    } else if (strpos($fn, 'rjmprogramming.com.au') !== false) {
    $rhs=explode('rjmprogramming.com.au' . explode('/', explode('rjmprogramming.com.au', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    } else if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
    $pth='/usr/bin/';
    }
    }
    if (file_exists($fn)) {
    $prefn=$fn;
    if ($contents == '') {
    $contents=file_get_contents($fn);
    }
    $fn=realpath($fn);
    if (strpos(strtolower($fn), '.xml') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    } else if (strpos(strtolower($fn), '.htm') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --html --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    //file_put_contents('xxx.xxx', $results);
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    }
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    } else {
    $contents='';
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    }
    }
    if ($contents != '') {
    $lines=explode("\n", $contents);
    for ($ii=1; $ii<=sizeof($lines); $ii++) {
    $precontents.='' . $ii . "\n";
    }
    }

    ?>

Cute, huh?!


Previous relevant XML Lint Validation Tutorial is shown below.

XML Lint Validation Tutorial

XML Lint Validation Tutorial

Do you remember when we discussed the Sanitizer API, talked about at Sanitizer API Primer Tutorial, regarding it as a web application HTML (and more) validation tool?

Well, we’ve based a new “validator” of HTML or XML using the XML Lint web application on what we did then, but this code needing to be …

  • under the auspices of a serverside scenario … ie. PHP … for us … calling on …
  • underlying operating system call such as (for HTML qsall.htm incoming data file) …

    xmllint --html --valid --noout ./qsall.htm

    … via …
  • shell_exec

… there’s not much left of the original HTML and Javascript!

We had a fun time with HTML textarea elements and scrolling with the resultant “first draft” xmllint_validation.php you might want to try for yourself supplying an HTML or XML URL of intetest. Why, in particular? Well, it was the first time that we remember trying to make practically useful …

  • a table cell (ie. td element) (the left of two) hosted …
  • two textarea element arrangement whereby, ideally. they view …
    1. side by side
    2. if one is scrolled the two identically scroll the same amount … (document.body outerHTML) HTML …
      <?php echo ”

      <body onload="s1 = document.getElementById('preincoming'); s2 = document.getElementById('incoming'); s1.addEventListener('scroll', select_scroll_1, false); s2.addEventListener('scroll', select_scroll_2, false);" data-onload='onl();'>
      <h1>XML Lint Validation <!--button onclick='trythis();' title='Try your own'>Usage</button--></h1>
      <h3>RJM Programming - June, 2024</h3>
      <form action=./xmllint_validation.php method=POST target=_self>
      <table style=width:95%; border=5>
      <tr><th colspan=2 style=text-align:center;>XML Lint validation of <input style=width:70%; onblur="if (this.value.length > 0) { document.getElementById('mysub').click(); }" name=htmlfile id=myhxfile placeholder='Please enter either HTML or XML file to validate ...' value="<?php echo str_replace('>','>',str_replace('<','<',$prefn)); ?>"></input></th></tr>
      <tr><th>Data to validate</th><th>XML Lint results</th></tr>
      <tr><td style=vertical-align:top;><textarea style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap;text-align:right; id=preincoming><?php echo str_replace('>','>',str_replace('<','<',$precontents)); ?></textarea><textarea onblur="if (this.value.length > 0 && '<?echo $fn; ?>' == '') { document.getElementById('mysub').click(); }" style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap; name=content id=incoming><?php echo str_replace('>','>',str_replace('<','<',$contents)); ?></textarea></td><td style=vertical-align:top;><textarea id=outgoing><?php echo str_replace('>','>',str_replace('<','<',$results)); ?></textarea></td></tr>
      <tr><td></td><td><input type=submit id=mysub style=display:<?php echo $vsnone; ?> value=Validate></input></td></tr>
      </table>
      </form>
      </body>

      “; ?>
      … uses Javascript …
      <?php echo ”

      var s1=null, s2=null;

      // Thanks to https://stackoverflow.com/questions/7108270/scrolling-2-different-elements-in-same-time
      function select_scroll_1(e) { s2.scrollTop = s1.scrollTop; }
      function select_scroll_2(e) { s1.scrollTop = s2.scrollTop; }

      “; ?>
      … so that …
    3. the left hand textarea contains code line numbers right aligned … to sidle up next to …
    4. the right hand textarea contains the code (HTML or XML) being validated by xmllint

    … while …

  • the right hand table cell contains the xmllint validation (of HTML or XML) results

… had us, in practice, thanking our lucky stars that …

  1. textarea elements are resizeable
  2. you can simulate “some cockpit action” aligning them vertically … Jim?!


Previous relevant Sanitizer API Primer Tutorial is shown below.

Sanitizer API Primer Tutorial

Sanitizer API Primer Tutorial

Today we’re roadtesting the Sanitizer API

The HTML Sanitizer API allow developers to take untrusted strings of HTML and Document or DocumentFragment objects, and sanitize them for safe insertion into a document’s DOM.

… as another validation idea for HTML to add to our previous HTML Online Validation Tidy Errors Tutorial efforts.

Perhaps you’d like to try the “Usage” button of the proof of concept web application below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

XML Lint Validation Browsing Tutorial

XML Lint Validation Browsing Tutorial

XML Lint Validation Browsing Tutorial

Yesterday’s XML Lint Validation Tutorial had us starting out on a discovery tour of XML Lint, yesterday …

  • starting with an HTML or XML URL of interest incoming data way … and today, we add onto that …
  • a local HTML or XMLfile browsing means of defining your input data into …

our changed “second draft” xmllint_validation.php you might want to try for yourself, helped out by a tweaked client_browsing.htm client side HTML and Javascript inhouse helper.

Again, we see, into another way to yesterday’s work, how useful in a textarea element, in that it can facilitate the way …

  • HTML and XML data can be input via populating the textarea innerHTML attribute … which flows through to a …
  • textarea value attribute value where any < is mapped to &lt; and > is mapped to &gt; … ready for …
  • an HTML form hosted textarea, given a filled in name attribute be able to share this data to that form’s action attributed value …
    <?php

    function ronecheck() {
    if (document.getElementById('result1').innerHTML != '') {
    document.getElementById('incoming').innerHTML=document.getElementById('result1').value;
    document.getElementById('result1').innerHTML='';
    document.getElementById('result1').value='';
    document.getElementById('myhxfile').name='xx';
    document.getElementById('mysub').click();
    }
    }

    ?>
    … (in our case being the same PHP) …
  • able to be processed by recall PHP interventional code …
    <?php

    $vsnone='none';
    $prefn='Please enter either HTML or XML file to validate ...';
    $pth='';
    $rn='' .rand(1,78477554);
    $results='';
    $precontents='';
    $contents='';
    $fn='';
    if (!isset($_GET['htmlfile']) && isset($_GET['content'])) {
    $_GET['htmlfile']=$_GET['content'];
    }
    if (!isset($_POST['htmlfile']) && isset($_POST['content'])) {
    $_POST['htmlfile']=$_POST['content'];
    }
    if (isset($_GET['htmlfile'])) {
    if (substr(trim(urldecode($_GET['htmlfile'])) . ' ', 0, 1) == '<') {
    $contents=trim(str_replace('+',' ',urldecode($_GET['htmlfile'])));
    if (strpos(strtolower(explode('>', $contents)[0]), 'html') !== false) {
    $fn='/tmp/html_' . $rn . '.html';
    } else if (strpos(strtolower(explode('>', $contents)[0]), 'xml') !== false) {
    $fn='/tmp/xml_' . $rn . '.xml';
    }
    file_put_contents($fn, $contents);
    } else {
    $fn=str_replace('+',' ',urldecode($_GET['htmlfile']));
    }
    if ($fn != '') {
    if (strpos($fn, 'localhost') !== false) {
    $rhs=explode('localhost' . explode('/', explode('localhost', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    $pth='/usr/bin/';
    } else if (strpos($fn, 'rjmprogramming.com.au') !== false) {
    $rhs=explode('rjmprogramming.com.au' . explode('/', explode('rjmprogramming.com.au', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    } else if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
    $pth='/usr/bin/';
    }
    }
    if (file_exists($fn)) {
    if ($contents == '') {
    $contents=file_get_contents($fn);
    }
    $prefn=$fn;
    $fn=realpath($fn);
    if (strpos(strtolower($fn), '.xml') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    } else if (strpos(strtolower($fn), '.htm') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --html --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    }
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    } else {
    $contents='';
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    }
    } else if (isset($_POST['htmlfile'])) {
    if (substr(trim(urldecode($_POST['htmlfile'])) . ' ', 0, 1) == '<') {
    $contents=trim(str_replace('+',' ',urldecode($_POST['htmlfile'])));
    if (strpos(strtolower(explode('>', $contents)[0]), 'html') !== false) {
    $fn='/tmp/html_' . $rn . '.html';
    } else if (strpos(strtolower(explode('>', $contents)[0]), 'xml') !== false) {
    $fn='/tmp/xml_' . $rn . '.xml';
    }
    file_put_contents($fn, $contents);
    } else {
    $fn=str_replace('+',' ',urldecode($_POST['htmlfile']));
    }
    if ($fn != '') {
    if (strpos($fn, 'localhost') !== false) {
    $rhs=explode('localhost' . explode('/', explode('localhost', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    $pth='/usr/bin/';
    } else if (strpos($fn, 'rjmprogramming.com.au') !== false) {
    $rhs=explode('rjmprogramming.com.au' . explode('/', explode('rjmprogramming.com.au', $fn)[1])[0], $fn)[1];
    $fn=$_SERVER['DOCUMENT_ROOT'] . $rhs;
    } else if (strpos($_SERVER['SERVER_NAME'], 'localhost') !== false) {
    $pth='/usr/bin/';
    }
    }
    if (file_exists($fn)) {
    $prefn=$fn;
    if ($contents == '') {
    $contents=file_get_contents($fn);
    }
    $fn=realpath($fn);
    if (strpos(strtolower($fn), '.xml') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    } else if (strpos(strtolower($fn), '.htm') !== false) {
    $vsnone='block';
    $results=shell_exec($pth . 'xmllint --html --valid --noout ' . $fn . ' 2> ' . ' ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err')) {
    $results.="\n";
    $results.=file_get_contents(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    //file_put_contents('xxx.xxx', $results);
    unlink(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'xmllint.err');
    }
    }
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    } else {
    $contents='';
    if (strpos($fn, '/tmp/') !== false) { unlink($fn); }
    }
    }
    if ($contents != '') {
    $lines=explode("\n", $contents);
    for ($ii=1; $ii<=sizeof($lines); $ii++) {
    $precontents.='' . $ii . "\n";
    }
    }

    ?>

Cute, huh?!


Previous relevant XML Lint Validation Tutorial is shown below.

XML Lint Validation Tutorial

XML Lint Validation Tutorial

Do you remember when we discussed the Sanitizer API, talked about at Sanitizer API Primer Tutorial, regarding it as a web application HTML (and more) validation tool?

Well, we’ve based a new “validator” of HTML or XML using the XML Lint web application on what we did then, but this code needing to be …

  • under the auspices of a serverside scenario … ie. PHP … for us … calling on …
  • underlying operating system call such as (for HTML qsall.htm incoming data file) …

    xmllint --html --valid --noout ./qsall.htm

    … via …
  • shell_exec

… there’s not much left of the original HTML and Javascript!

We had a fun time with HTML textarea elements and scrolling with the resultant “first draft” xmllint_validation.php you might want to try for yourself supplying an HTML or XML URL of intetest. Why, in particular? Well, it was the first time that we remember trying to make practically useful …

  • a table cell (ie. td element) (the left of two) hosted …
  • two textarea element arrangement whereby, ideally. they view …
    1. side by side
    2. if one is scrolled the two identically scroll the same amount … (document.body outerHTML) HTML …
      <?php echo ”

      <body onload="s1 = document.getElementById('preincoming'); s2 = document.getElementById('incoming'); s1.addEventListener('scroll', select_scroll_1, false); s2.addEventListener('scroll', select_scroll_2, false);" data-onload='onl();'>
      <h1>XML Lint Validation <!--button onclick='trythis();' title='Try your own'>Usage</button--></h1>
      <h3>RJM Programming - June, 2024</h3>
      <form action=./xmllint_validation.php method=POST target=_self>
      <table style=width:95%; border=5>
      <tr><th colspan=2 style=text-align:center;>XML Lint validation of <input style=width:70%; onblur="if (this.value.length > 0) { document.getElementById('mysub').click(); }" name=htmlfile id=myhxfile placeholder='Please enter either HTML or XML file to validate ...' value="<?php echo str_replace('>','>',str_replace('<','<',$prefn)); ?>"></input></th></tr>
      <tr><th>Data to validate</th><th>XML Lint results</th></tr>
      <tr><td style=vertical-align:top;><textarea style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap;text-align:right; id=preincoming><?php echo str_replace('>','>',str_replace('<','<',$precontents)); ?></textarea><textarea onblur="if (this.value.length > 0 && '<?echo $fn; ?>' == '') { document.getElementById('mysub').click(); }" style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap; name=content id=incoming><?php echo str_replace('>','>',str_replace('<','<',$contents)); ?></textarea></td><td style=vertical-align:top;><textarea id=outgoing><?php echo str_replace('>','>',str_replace('<','<',$results)); ?></textarea></td></tr>
      <tr><td></td><td><input type=submit id=mysub style=display:<?php echo $vsnone; ?> value=Validate></input></td></tr>
      </table>
      </form>
      </body>

      “; ?>
      … uses Javascript …
      <?php echo ”

      var s1=null, s2=null;

      // Thanks to https://stackoverflow.com/questions/7108270/scrolling-2-different-elements-in-same-time
      function select_scroll_1(e) { s2.scrollTop = s1.scrollTop; }
      function select_scroll_2(e) { s1.scrollTop = s2.scrollTop; }

      “; ?>
      … so that …
    3. the left hand textarea contains code line numbers right aligned … to sidle up next to …
    4. the right hand textarea contains the code (HTML or XML) being validated by xmllint

    … while …

  • the right hand table cell contains the xmllint validation (of HTML or XML) results

… had us, in practice, thanking our lucky stars that …

  1. textarea elements are resizeable
  2. you can simulate “some cockpit action” aligning them vertically … Jim?!


Previous relevant Sanitizer API Primer Tutorial is shown below.

Sanitizer API Primer Tutorial

Sanitizer API Primer Tutorial

Today we’re roadtesting the Sanitizer API

The HTML Sanitizer API allow developers to take untrusted strings of HTML and Document or DocumentFragment objects, and sanitize them for safe insertion into a document’s DOM.

… as another validation idea for HTML to add to our previous HTML Online Validation Tidy Errors Tutorial efforts.

Perhaps you’d like to try the “Usage” button of the proof of concept web application below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

XML Lint Validation Tutorial

XML Lint Validation Tutorial

XML Lint Validation Tutorial

Do you remember when we discussed the Sanitizer API, talked about at Sanitizer API Primer Tutorial, regarding it as a web application HTML (and more) validation tool?

Well, we’ve based a new “validator” of HTML or XML using the XML Lint web application on what we did then, but this code needing to be …

  • under the auspices of a serverside scenario … ie. PHP … for us … calling on …
  • underlying operating system call such as (for HTML qsall.htm incoming data file) …

    xmllint --html --valid --noout ./qsall.htm

    … via …
  • shell_exec

… there’s not much left of the original HTML and Javascript!

We had a fun time with HTML textarea elements and scrolling with the resultant “first draft” xmllint_validation.php you might want to try for yourself supplying an HTML or XML URL of intetest. Why, in particular? Well, it was the first time that we remember trying to make practically useful …

  • a table cell (ie. td element) (the left of two) hosted …
  • two textarea element arrangement whereby, ideally. they view …
    1. side by side
    2. if one is scrolled the two identically scroll the same amount … (document.body outerHTML) HTML …
      <?php echo ”

      <body onload="s1 = document.getElementById('preincoming'); s2 = document.getElementById('incoming'); s1.addEventListener('scroll', select_scroll_1, false); s2.addEventListener('scroll', select_scroll_2, false);" data-onload='onl();'>
      <h1>XML Lint Validation <!--button onclick='trythis();' title='Try your own'>Usage</button--></h1>
      <h3>RJM Programming - June, 2024</h3>
      <form action=./xmllint_validation.php method=POST target=_self>
      <table style=width:95%; border=5>
      <tr><th colspan=2 style=text-align:center;>XML Lint validation of <input style=width:70%; onblur="if (this.value.length > 0) { document.getElementById('mysub').click(); }" name=htmlfile id=myhxfile placeholder='Please enter either HTML or XML file to validate ...' value="<?php echo str_replace('>','>',str_replace('<','<',$prefn)); ?>"></input></th></tr>
      <tr><th>Data to validate</th><th>XML Lint results</th></tr>
      <tr><td style=vertical-align:top;><textarea style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap;text-align:right; id=preincoming><?php echo str_replace('>','>',str_replace('<','<',$precontents)); ?></textarea><textarea onblur="if (this.value.length > 0 && '<?echo $fn; ?>' == '') { document.getElementById('mysub').click(); }" style=font-size:8px;display:inline-block;overflow-x:clip;text-wrap:nowrap; name=content id=incoming><?php echo str_replace('>','>',str_replace('<','<',$contents)); ?></textarea></td><td style=vertical-align:top;><textarea id=outgoing><?php echo str_replace('>','>',str_replace('<','<',$results)); ?></textarea></td></tr>
      <tr><td></td><td><input type=submit id=mysub style=display:<?php echo $vsnone; ?> value=Validate></input></td></tr>
      </table>
      </form>
      </body>

      “; ?>
      … uses Javascript …
      <?php echo ”

      var s1=null, s2=null;

      // Thanks to https://stackoverflow.com/questions/7108270/scrolling-2-different-elements-in-same-time
      function select_scroll_1(e) { s2.scrollTop = s1.scrollTop; }
      function select_scroll_2(e) { s1.scrollTop = s2.scrollTop; }

      “; ?>
      … so that …
    3. the left hand textarea contains code line numbers right aligned … to sidle up next to …
    4. the right hand textarea contains the code (HTML or XML) being validated by xmllint

    … while …

  • the right hand table cell contains the xmllint validation (of HTML or XML) results

… had us, in practice, thanking our lucky stars that …

  1. textarea elements are resizeable
  2. you can simulate “some cockpit action” aligning them vertically … Jim?!


Previous relevant Sanitizer API Primer Tutorial is shown below.

Sanitizer API Primer Tutorial

Sanitizer API Primer Tutorial

Today we’re roadtesting the Sanitizer API

The HTML Sanitizer API allow developers to take untrusted strings of HTML and Document or DocumentFragment objects, and sanitize them for safe insertion into a document’s DOM.

… as another validation idea for HTML to add to our previous HTML Online Validation Tidy Errors Tutorial efforts.

Perhaps you’d like to try the “Usage” button of the proof of concept web application below …

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , | Leave a comment

NetNewsWire Web Feed macOS Safari Primer Tutorial

NetNewsWire Web Feed macOS Safari Primer Tutorial

NetNewsWire Web Feed macOS Safari Primer Tutorial

In the same “RSS feed” feel of FeedBurner Web Feed Primer Tutorial, the other day …

  • on this macOS MacBook Air … using …
  • Safari web browser … we had occasion to type into the address bar …
  • https://www.rjmprogramming.com.au/ITblog/tag/document/feed/
  • to which we received the advisory message …

    This is a link to an RSS feed. Would you like to search the App Store for Apps that can display RSS feeds?

    … different to the (less worrying) behaviour on Google Chrome …

So we went looking for a free macOS and Safari RSS feed reader and came up with the great looking NetNewsWire for this purpose, thanks. It looks great!


Previous relevant FeedBurner Web Feed Primer Tutorial is shown below.

FeedBurner Web Feed Primer Tutorial

FeedBurner Web Feed Primer Tutorial

We’ve opened a FeedBurner web feed management provider account for the Robert James Metcalfe Blog, our WordPress 4.1.1 blog at this link. Let’s see what Wikipedia says about FeedBurner, which Google acquired on 3rd June 2007, here and below …

FeedBurner is a web feed management provider launched in 2004.[1] FeedBurner was founded by Dick Costolo, Eric Lunt, Steve Olechowski, and Matt Shobe. Costolo is a University of Michigan graduate, and was CEO of Twitter from 2010 to 2015. FeedBurner provides custom RSS feeds and management tools to bloggers, podcasters, and other web-based content publishers.

Web feed management providers like FeedBurner are pretty important to bloggers because a lot of web traffic to blogs these days does not come from the user finding the blog news via their favourites or out of habit each day, but rather from “feeds” they have subscribed to, that they use the precis headline of to decide whether they want to read further on a topic of interest or disgust or whatever or what…everrrrrr.

It was fairly straightforward as a Google Gmail user to sign up for the Robert James Metcalfe Blog feed to be registered with FeedBurner. More or less just follow your nose with a visit to http://feedburner.com … but what was a bit surprising was the next day’s realization that just because some content looks okay in HTML it would necessarily be totally okay for FeedBurner which requires that content to validate in terms of XML data as well.

Now here is where the FeedBurner “Troubleshootize” tab functionalities called (for the Robert James Metcalfe Blog feed) …

… can come into their own to show you any potential problems.

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Operating System, Software, Tutorials | Tagged , , , , , , , , , , | Leave a comment

Australian Geographical Quiz Scrolling Tutorial

Australian Geographical Quiz Scrolling Tutorial

Australian Geographical Quiz Scrolling Tutorial

We were a little gobsmacked revisiting the 2017 era Australian Geographical Quiz Context Tutorial quiz web application (and thanks to Australian Geographic website here) that looking through the code … arrrgggghhh … the string …

.scroll

… was missing. Why should it be there? Well, on a re-run through of how the Australian Geographical Quiz web application worked, we were asked to click on …

Wilsons Promontory

… which did not send us into a tizzy by itself. Oh no! We never panic?! Even without the apostrophe in Wilsons we handled that … no worries … we realize that could have been because two (or more) guys or gals or both called Wilson were standing together at just the right time and place (or sent there by Karen) when a “promontory” needed naming … no problems. No, what caused our “too fragile” web application diffs was the way we had to scroll down to that esteemed Victorian coastal location in our (temporarily, mind you) less esteemious web application. We got funny places mentioned as our nearest “place of click”, and it was then the “true horror” happened (ie. with our code scouring reveal) … no “false horror” around here … no … it was “true” all right … we’re here to tell you! Any obs! Okay?!

The fix, you ask?!

Glad you asked! Take a look at (where we also catered for mobile platforms better too) …


function icheck(evt) {
if (realclick) {
var x,y;
if (evt.touches) {
if (evt.touches[0].pageX) {
x = (eval(evt.touches[0].pageX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.touches[0].pageY + document.body.scrollTop * 1) * 1);
} else {
x = (eval(evt.touches[0].clientX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.touches[0].clientY + document.body.scrollTop * 1) * 1);
}
} else
if (evt.clientX || evt.clientY) {
x = (eval(evt.clientX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.clientY + document.body.scrollTop * 1) * 1);
} else {
x = (eval(evt.pageX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.pageY + document.body.scrollTop * 1) * 1);
}
var distco=((x - midcoords[placepick][0]) * (x - midcoords[placepick][0])) + ((y - midcoords[placepick][1]) * (y - midcoords[placepick][1]));
var halfpoint='';

var davw=' ... you are very cold ';
if (distco <= verywarm) {
halfpoint='0.5';
davw=" ... you are very warm (and it's possible there is an overlap, so you score the 0.5 choosing this with OK button) ";
} else if (distco <= warm) {
davw=' ... you are warm ';
} else if (distco <= cool) {
davw=' ... you are cool ';
} else if (distco <= cold) {
davw=' ... you are cold ';
}

var nearestplace='';
var nearestdistco=-1;
for (var jwhich=0; jwhich<midcoords.length; jwhich++) {
distco=((midcoords[jwhich][0] - x) * (midcoords[jwhich][0] - x)) + ((midcoords[jwhich][1] - y) * (midcoords[jwhich][1] - y));
if (jwhich == 0) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
} else if (distco < nearestdistco) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
}
}
goes++;
if (nearestplace == placechosen.replace(/_/g,' ')) {
score+=factor;
setTimeout(resetit, 200);
setTimeout(pickone,1000);
} else {
var ans=prompt('You clicked nearest to ' + nearestplace + ' (0 for YouTube search, -0 for Australian Geographic search, +0 Both, 0.0 for Context in Map Legend) but we wanted you to identify ' + placechosen.replace(/_/g,' ') + ' (1 for YouTube search, -1 for Australian Geographic search, +1 Both, 1.1 for Context in Map Legend)' + davw + ' ... try again ... or ... Choose to Cancel', halfpoint);
if (ans == null) {
//alert(92);
setTimeout(pickone,2000);
} else if (ans == '0.0') {
if (lgo != null) lgo.close();
lgo=window.open(pathto + 'legend_via_map.htm?url=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0]) + '&tarea=&submit=Create+Legend+for+HTML+Map+Data&whereami=where-am-i&whatami=what-am-i&secret=secret#' + nearestplace.replace(/ /g,'_'), '_blank');
} else if (ans == '1.1') {
if (lgo != null) lgo.close();
lgo=window.open(pathto + 'legend_via_map.htm?url=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0]) + '&tarea=&submit=Create+Legend+for+HTML+Map+Data&whereami=where-am-i&whatami=what-am-i&secret=secret#' + placechosen.replace(/ /g,'_'), '_blank');
} else if (ans == '-0') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
} else if (ans == '-1') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
} else if (ans.replace('+','') == '0') {
if (yto == null) {
if (document.title.indexOf('Country ') != 0) document.title='Country ' + document.title;
document.getElementById('youtube').innerHTML='<a ontouchstart=" realclick=false; setTimeout(resetit,1000); " onclick=" realclick=false; setTimeout(resetit,1000);" title="Back to top" href="#iag">Back to top</a><iframe style=width:900px;height:700px; id=iyto src="' + pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20') + '"></iframe>';
yto=document.getElementById('iyto');
} else {
yto.src=pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20');
}
if (ans == '+0') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
}
location.href='#iyto';
} else if (ans.replace('+','') == '1') {
if (yto == null) {
if (document.title.indexOf('Country ') != 0) document.title='Country ' + document.title;
document.getElementById('youtube').innerHTML='<a ontouchstart=" realclick=false; setTimeout(resetit,1000); " onclick=" realclick=false; setTimeout(resetit,1000);" title="Back to top" href="#iag">Back to top</a><iframe style=width:900px;height:700px; id=iyto src="' + pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20') + '"></iframe>';
yto=document.getElementById('iyto');
} else {
yto.src=pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20');
}
if (ans == '+1') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
}
location.href='#iyto';
} else if (ans == '0.5') {
score+=0.5;
setTimeout(pickone,2000);
}
setTimeout(resetit, 200);
}
document.getElementById('score').innerHTML='Score: ' + score + '/' + goes;
}
return '';
}

… in agmap.htm, changed in this way using the Australian Geographical Quiz web application.


Previous relevant Australian Geographical Quiz Context Tutorial is shown below.

Australian Geographical Quiz Context Tutorial

Australian Geographical Quiz Context Tutorial

We are continuing on with our Australian Geographic quiz today, building on our Australian Geographical Quiz Primer Tutorial start yesterday, with some added functionality to assist with “finding out more”. Which is natural for us when we come upon information we have never heard of before. What the “net” has most helped us out with in this respect is its potential as a reference source with …

  • Search Engine websites
  • Encyclopaedic websites such as Wikipedia
  • Research websites
  • Education websites
  • Video repositories

… and today we are going to (allow an) interface to the search functionality of the Australian Geographic website, in addition to the biggest online Video repository, YouTube, and use their great API to embed YouTube videos within HTML iframe elements on your webpage. Perusing YouTube you may have noticed that for many years now at YouTube Share button options, there have been ways to have YouTube help you to “cut” the video embedding HTML code necessary to display a video. That is the basis behind the API, but the API also facilitates …

  • Sequencing videos
  • Stop and start and pause
  • Durations
  • Titles
  • Volume
  • Resizing

… and we’d like to direct you to YouTube API Iframe Synchronicity Resizing Tutorial for further reading here.

Now, as far as “context” goes, coming back to our blog posting title today, sometimes a map can be a bit of an overwhelmingly big thing to take in as the one data source, so we’ve also added as an “interfacing” additional functionality option, the chance for the user to latch onto the work we did with map legends and talked about at Legend for and from HTML Map Element Web Server Tutorial and other related blog postings. Legends turn the map “big” picture into a whole lot of place specific small pictures, with the advantage today, at least with the “Difficult” mode of play, the Australian states are colour coded, so in the legend you can display it will “lob” you onto your specific place of interest, and the background colouring will give you some hints as to where this is in the context of the “bigger picture” map also displayed for you to the left of the map legend.

To understand this more in “context” … chortle, chortle … why not try the Australian Geography quiz yourself at this live run link? Or perhaps peruse the HTML and Javascript code you could call agmap.htm changed in this way for today’s added functionalities? Also changing that little bit for the concept of processing incoming document.URL URLs containing a specially constructed “Australian Geography Quiz” “branded” hashtag (#) appendage as the means to highlight a “lobbed to” legend placename was the HTML code you could call legend_via_map.htm changing in this way to achieve that interfacing logic.


Previous relevant Australian Geographical Quiz Primer Tutorial is shown below.

Australian Geographical Quiz Primer Tutorial

Australian Geographical Quiz Primer Tutorial

We have some similar ideas going on today, with our new web application quiz/game, to those of ESL Vocabulary Getting Warmer Image Tutorial as shown below, as can be summarised by …

  • use of the one underlying background image … coupled with …
  • use of HTML map element on top of that … created via …
  • the brilliant, the stupendous Mobilefish website helper … thanks … to arrive at a …
  • “getting warmer” type of quiz related, today, to Australian Geography

… the underlying map image for which we’ve based on one from the stupendous, the brilliant Australian Geographic magazine and website, so thanks.

A thing different in today’s work, apart from the inherent different look and array manipulations you look and act differently with, over time, with the code, is that we have two images …

  1. original image photographed with an iPad … for an “Easier” gameplay level of difficulty … as well as a …
  2. “confused up”/”messed up” … call it what you will … image version put through a session on Gimp to …
    • Free Select Cut … and …
    • Free Select Gaussian Blur

    … in order to arrive at an image for a “Difficult” gameplay level of difficulty (where there is less on the map image to help the user

… presented to the player of the web application “Australian Geography” game in an HTML select “dropdown” choice.

The other bit extra we’ve done today, because the HTML map element has not been designed to cover the whole rectangle of the image, is to harness the document.body onclick event (fired off via the HTML <body onload=’atstart();’ ontouchstart=’icheck(event);’ onclick=’icheck(event);’>) to check for (web application game) clicks (or touches) that are not …

  • HTML select element based clicks … nor …
  • other HTML map element HTML area element clicks

… and if so, record that click event’s mouse (x,y) co-ordinates and report on this in a similar way to the “HTML map element HTML area element clicks”, except that we have no link to a name for their click (whereas we can glean a name off the HTML area element alt property for those HTML map element HTML area element clicks), and so we inform the user of the “nearest” place they clicked (or touched) near … as per (Javascript DOM code) …


function icheck(evt) {
if (realclick) {
var x,y;
if (evt.clientX || evt.clientY) {
x = evt.clientX;
y = evt.clientY;
} else {
x = evt.pageX;
y = evt.pageY;
}
var distco=((x - midcoords[placepick][0]) * (x - midcoords[placepick][0])) + ((y - midcoords[placepick][1]) * (y - midcoords[placepick][1]));
var halfpoint='';

var davw=' ... you are very cold ';
if (distco <= verywarm) {
halfpoint='0.5';
davw=' ... you are very warm (and its possible there is an overlap, so you score the 0.5 choosing this with OK button) ';
} else if (distco <= warm) {
davw=' ... you are warm ';
} else if (distco <= cool) {
davw=' ... you are cool ';
} else if (distco <= cold) {
davw=' ... you are cold ';
}

var nearestplace='';
var nearestdistco=-1;
for (var jwhich=0; jwhich<midcoords.length; jwhich++) {
distco=((midcoords[jwhich][0] - x) * (midcoords[jwhich][0] - x)) + ((midcoords[jwhich][1] - y) * (midcoords[jwhich][1] - y));
if (jwhich == 0) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
} else if (distco < nearestdistco) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
}
}
goes++;
var ans=prompt('You clicked nearest to ' + nearestplace + ' but we wanted you to identify ' + placechosen.replace(/_/g,' ') + davw + ' ... try again ... or ... Choose to Cancel', halfpoint);
if (ans == null) {
//alert(92);
setTimeout(pickone,2000);
} else if (ans == '0.5') {
score+=0.5;
setTimeout(pickone,2000);
}
setTimeout(resetit, 200);
document.getElementById('score').innerHTML='Score: ' + score + '/' + goes;
}
return '';
}

The Javascript realclick global variable above is set to false by those other HTML select element and/or HTML map element area element click (or touch) events, and then a “setTimeout(resetit,1000);” (for example) would put realclick global variable back to its usual true value.

Why not try the Australian Geography quiz yourself at this live run link? Or peruse the HTML and Javascript code you could call agmap.html perhaps? By the way, this quiz is designed not to ask about the more populous regions or places of Australia, but more your outback or national park or adventure thought places.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Trust This Computer Issue on iPhone Tutorial

Just Javascript Card Game iPhone Debugging Tutorial

Trust This Computer Issue on iPhone Tutorial

We think we introduced a problem with the way our iPhone charges (or is hard to) recently, and we think we got “out of synch” with using the iPhone as a debugging tool (as we show with Just Javascript Card Game iPhone Debugging Tutorial), connected via an Apple white lead to the USB port of a MacBook Air.

The symptoms of the look of our version of the problem, was that using a particular combination of …

  • Apple white lead
  • MacBook Air USB port

… and us using those two in combination, with a powered up MacBook Air, was charging the iPhone, it would be interrupted constantly in its charging by a “not happening” attempt to bring up a …

Trust this Computer

… alert looking somewhat like …

… alert box regarding the MacBook Air (probably caused by that “out of synch” event during a debugging session). The iPhone constantly buzzes (technically, “vibrates”) every five seconds or so, and even when we got the alert box to show after first remedial steps (suggested by Apple) below …

  1. Go to Settings, then tap General.
  2. Tap Transfer or Reset [Device].
  3. Tap Reset, then tap Reset Location & Privacy.

… we got to a validation 6-8-digit number keyboard screen …

… (after Powering On and Off) that didn’t hang around long enough either (between buzzes) until …

… and we got long enough time to answer that validation 6-8-digit number keyboard screen … phew! Normal behaviour now, hopefully for a good while?!


Previous relevant Just Javascript Card Game iPhone Debugging Tutorial is shown below.

Just Javascript Card Game iPhone Debugging Tutorial

Just Javascript Card Game iPhone Debugging Tutorial

Before yesterday’s Just Javascript Card Game CSS Offerings Tutorial there was the day before yesterday’s Just Javascript Card Game User CSS Tutorial which …

  • introduced an error on mobile devices …
  • not apparent on the MacBook Air we were coding on

… the salutary lesson being that you need to test on platforms you have available to you because our code is sprinkled with plenty of Javascript …


if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
// comes here if most mobile platforms
}

… “if” tests where the “mobile platform” code parts way with the “non-mobile platform” code. This is very likely in the scenario of you creating a game web application involving graphics.

Being the Apple afficianados we are we tend to want to debug the scenario of an iPhone blank screen issue via …

  1. be on MacBook Air Safari web browser …
  2. also be on iPhone Safari web browser at the address https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=2
  3. connect the two with an Apple white lead that is USB at the MacBook Air end and the other end is that same recharging port connection …
  4. back at MacBook Air Safari web browser in the Develop menu you should see the name of the iPhone (eg. “Robert’s iPhone”) appear in the list so go there now …
  5. if the only option is something like “Allow for Development” over at the iPhone you might have a Trust vs Do Not Trust answer to make, and we advise you to be trusting, at which point …
  6. back at MacBook Air Safari web browser in the Develop menu -> [iPhone device name] submenu it should show an option for that https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=2 webpage, and so choose that option …
  7. you may want to refresh the iPhone web address …
  8. back at MacBook Air Safari web browser in the Develop menu -> [iPhone device name] submenu -> [https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=2] subsubmenu be in the Console tab …
  9. we eventually got the error message of use just using the iPhone web application until the line number helped us track down and debug the issue

Also, today, we’ve added to yesterday’s …

  1. accept from then on the presented CSS styling option
  2. reject to restore original CSS styling
  3. wait to be offered the next CSS styling suggestion
  4. enter their own user additional styling CSS
  5. with “accept” and “enter their own” options above spaces at end of user entry signify that window.localStorage should be used to be able to save and recall this CSS for future use

… making use of new Javascript functions in the changed


function checkls() {
if (window.localStorage) {
if (('' + window.localStorage.getItem('cardscsseffect')).replace(/^null$/g,'').replace(/^undefined$/g,'') != '') {
csseffects=('' + decodeURIComponent(window.localStorage.getItem('cardscsseffect')).trim() + ';').replace(';;',';').replace('; ;',';');
document.head.innerHTML+='<style> html { ' + csseffects + ' } </style>';
if (csseffects.replace(/\ /g,'').toLowerCase() == 'filter:none;') {
csseffects='';
window.localStorage.removeItem('cardscsseffect');
return ' are CSS and add spaces to remember.';
} else {
csseffects=' ' + csseffects;
}
return ' ( eg. filter:none; ) override CSS ' + csseffects.trim();
}
}
return ' are CSS and add spaces to remember.';
}

function recallornot(csseffect, iffalsesavetocookie) {
if (!iffalsesavetocookie && window.localStorage) {
if (('' + window.localStorage.getItem('cardscsseffect')).replace(/^null$/g,'').replace(/^undefined$/g,'') != '') {
window.localStorage.removeItem('cardscsseffect');
}
window.localStorage.setItem('cardscsseffect', encodeURIComponent((csseffect.trim() + ';').replace(';;',';')));
}
return csseffect;
}

… code in cards_usefocus.html code behind the “Just Javascript” Memories Card Game or live run with single window (good for mobile) or default live run (for your platform, and if non-mobile it will try child popup windows).



If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

Posted in eLearning, Hardware, iOS, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment