Ffmpeg User Defined Video Editing Sharing Tutorial

Ffmpeg User Defined Video Editing Sharing Tutorial

Ffmpeg User Defined Video Editing Sharing Tutorial

Sharing options for video based data are often more restrictive regarding email and SMS conduits, but we’ll still go ahead with a …

  • “a” link “mailto:” (for emails) or “sms:” (for SMS) methodology …
  • email subject containing ffmpeg command used for an output video mode of sharing … or …
  • input video mode of sharing before any ffmpeg involvement … based on …
  • email or SMS links where the video data URI (as necessary) is hashtagged

… set of ideas to try out, even though it is only likely to work for shorter videos. The other more obvious sharing mechanism is to download video data via right click options the web browser product you are using offers anyway. And another sharing idea, independent, and working for input videos is to browse for a video using the helper web application from yesterday, and use its Share API based button below the browsing button to share that input video using one of …

  • Mail
  • Messages
  • AirDrop
  • Notes
  • Simulator
  • Freeform

… on our macOS Safari web browser here on a MacBook Air.

Further to yesterday’s Ffmpeg User Defined Browsed Video Editing Tutorial, then, we have some new (PHP writes) Javascript functions …

<?php echo ”

function smsit() {
var smsno=prompt('Please enter SMS number.', '');
if (smsno != null) {
if (document.getElementById('cto').title.indexOf('data:') == 0) {
document.getElementById('asms').href='sms:' + smsno + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#vcont=' + document.getElementById('cto').title);
} else {
document.getElementById('asms').href='sms:' + smsno + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#vcont=' + document.getElementById('resultav').value);
}
document.getElementById('asms').click();
}
}


function emailit() {
var emailaddr=prompt('Please enter Email address.', '');
if (emailaddr != null) {
if (document.getElementById('cto').title.indexOf('data:') == 0) {
document.getElementById('aemail').href='mailto:' + emailaddr + '?subject=Ffmpeg%20Video' + encodeURIComponent(' ... ' + document.getElementById('mysubtwo').value.replace(/^Display$/g,'')) + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#vcont=' + document.getElementById('cto').title);
} else {
document.getElementById('aemail').href='mailto:' + emailaddr + '?subject=Ffmpeg%20Video' + encodeURIComponent(' ... ' + document.getElementById('mysubtwo').value.replace(/^Display$/g,'')) + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '#vcont=' + document.getElementById('resultav').value);
}
document.getElementById('aemail').click();
}
}

function documentgetElementByIdmysubpclick() { // new arrangement for the programmatic click of form submit button
if (eval('' + document.getElementById('resultav').value.length) < 300) {
document.getElementById('myiftwo').src=document.URL.split('?')[0].split('#')[0] + '?becomes=' + encodeURIComponent(document.getElementById('becomes').value) + '&browsed=' + encodeURIComponent(document.getElementById('resultav').value);
} else {
document.getElementById('mysubp').click();
}
}

“; ?>

… in our changed third draft of Your Own Ffmpeg Video Changes, which can be that much more useful in a new way in the AlmaLinux web server environment.


Previous relevant Ffmpeg User Defined Browsed Video Editing Tutorial is shown below.

Ffmpeg User Defined Browsed Video Editing Tutorial

Ffmpeg User Defined Browsed Video Editing Tutorial

Today’s work, onto yesterday’s Ffmpeg User Defined Video Editing Tutorial, is to loosen the restrictions regarding “input video file source” we had happening in that “first draft” incarnation of our Ffmpeg User Defined Video Editing web application.

In order to achieve this, we called on a previous Ffmpeg Install and Public Face Tutorial inspired change to our inhouse macos_ffmpeg_convert.php PHP web application, which can serve as our conduit to either/or …

  • browse for a video file off the user local operating system environment … or …
  • path to a web server placed video file … or …
  • URL to a video file

… extra means by which the user can define the “input video file source” that we’re loosening the shackles regarding usage.

To do this, we look for user actions (via PHP writing out Javascript) …

<?php echo ”

var lastpathc='';
var lastopathc='';
var lastvidc='';
var lastvalue='.m4v';
var exactvalue='';
var vext='.mp4';

function lookfor() {
vext='.mp4';
var thisext='';
if (document.getElementById('opath').value != '') {
if (lastopathc != document.getElementById('opath').value && document.getElementById('opath').title != document.getElementById('opath').value) {
lastopathc=document.getElementById('opath').value;
}
}
if (document.getElementById('path').value != '') {
if (lastpathc != document.getElementById('path').value) {
lastpathc=document.getElementById('path').value;
if (lastopathc == ' ') { lastopathc=document.getElementById('opath').value; }
}
}
if (lastopathc.trim() != '') {
thisext=(lastopathc + '.').split('.')[1].split('.')[0].trim();
if (thisext != '') {
document.getElementById('opath').title=lastopathc;
document.getElementById('path').title='video/' + thisext + ';' + lastpathc + lastopathc;
document.getElementById('resultav').value=lastpathc + lastopathc;
lastopathc=' ';
}
}
if (document.getElementById('resultav').value != '') {
if (lastvidc != document.getElementById('resultav').value) {
if ((document.getElementById('path').title + document.getElementById('resultav').value).indexOf('video/') != -1) {
if (document.getElementById('ifbrowse').src.indexOf('=') != -1) {
document.getElementById('myaltin').value=decodeURIComponent(document.getElementById('ifbrowse').src.split('=')[1].split('&')[0].split('#')[0]);
}
if ((document.getElementById('path').title + document.getElementById('resultav').value).indexOf('video/') != -1) {
if (vext.indexOf((document.getElementById('path').title + document.getElementById('resultav').value).split('video/')[1].split(';')[0].split(',')[0]) == -1) {
vext='.' + document.getElementById('resultav').value.split('video/')[1].split(';')[0].split(',')[0];
document.getElementById('myaltin').value=document.getElementById('myaltin').value.split('.')[0] + vext;
document.getElementById('becomes').value=document.getElementById('becomes').value.split('.')[0] + vext;
}
}
lastvidc=document.getElementById('resultav').value;
document.getElementById('resultav').title='rework';
document.getElementById('mysubp').click();
setTimeout(function(){
if (1 == 1) {
document.getElementById('divvid').innerHTML=\"<video id=myinvideo style=width:95%; controls><source id=myinsource type='video/\" + vext.substring(1) + \"' src='\" + document.getElementById('resultav').value + \"'></source></video>\";
} else {
document.getElementById('myinsource').src=document.getElementById('resultav').value;
}
}, 2000);
//setTimeout(function(){
//document.getElementById('resultav').value='';
//}, 20000);
//alert(lastvidc);
setTimeout(lookfor, 23000);
return '';
}
setTimeout(lookfor, 3000);
return '';
}
}
setTimeout(lookfor, 3000);
return '';
}

setTimeout(lookfor, 3000);

“; ?>

… and then arrange the /tmp/ placed temporary video data via …

<?php

if (isset($_POST['browsed']) && isset($_POST['becomes'])) {
$fgccont='';
//file_put_contents('xzm.xzm', '1');
$outtmpfile=str_replace('+',' ',urldecode($_POST['becomes']));
//file_put_contents('xzm2.xzm2', $outtmpfile);
$outext=explode('.', $outtmpfile)[-1 + sizeof(explode('.', $outtmpfile))];
//file_put_contents('xzm3.xzm3', str_replace(' ','+',urldecode($_POST['browsed'])));
if (strpos(('xwq' . $_POST['browsed']), 'xwqdata') !== false) {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), base64_decode(explode(";base64,", str_replace(' ','+',urldecode($_POST['browsed'])))[1]));
} else if (strpos(('xwq' . strtolower($_POST['browsed'])), 'xwqhttps') !== false) {
$fgccont=file_get_contents('http' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),5));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (strpos(('xwq' . strtolower($_POST['browsed'])), 'xwqhttp') !== false) {
$fgccont=file_get_contents('http' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),4));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (strpos(('xwq' . strtolower(str_replace('+',' ',urldecode($_POST['browsed'])))), 'xwq//') !== false) {
$fgccont=file_get_contents('http:' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),0));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (strpos(('xwq' . strtolower(str_replace('+',' ',urldecode($_POST['browsed'])))), 'xwqwww.') !== false) {
$fgccont=file_get_contents('http://' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),0));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (file_exists(str_replace('+',' ',urldecode($_POST['browsed'])))) {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), file_get_contents(str_replace('+',' ',urldecode($_POST['browsed']))));
}
//file_put_contents('xzm4.xzm4', explode(";base64,", str_replace(' ','+',urldecode($_POST['browsed'])))[1]);
exit;
}

?>

… all the while being helped out by a tweaked macos_ffmpeg_convert.php works Ffmpeg Converter Tool PHP web application helper to our changed second draft of Your Own Ffmpeg Video Changes, which can be that much more useful in a new way in the AlmaLinux web server environment.


Previous relevant Ffmpeg User Defined Video Editing Tutorial is shown below.

Ffmpeg User Defined Video Editing Tutorial

Ffmpeg User Defined Video Editing Tutorial

Today we’re combining video contents from …

  • yesterday’s Ffmpeg Helps iPhone Video to YouTube Tutorial … with …
  • our newly created public interface to ffmpeg with the “soon to be DNS version of rjmprogramming.com.au … but not yet” AlmaLinux Apache/PHP/MySql web server install we talked about at Ffmpeg Install and Public Face Tutorial … and …
  • IP address redirecting, as needed, ifconfig (via PHP shell_exec and $_SERVER[‘SERVER_ADDR’]) based logic …
    <?php

    $whereplace=shell_exec("ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'");
    if (strpos(($whereplace . ' ' . $_SERVER['SERVER_ADDR']), '65.254.92.213') !== false) {
    $sv='/usr/bin/ffmpeg';
    header('Location: https://65.254.95.247/PHP/tmp_ffmpeg.php'); //$smallpath='https://65.254.95.247/PHP/'; //header('Location: https://65.254.95.247/PHP/tmp_ffmpeg.php');
    exit; //exit;
    }

    ?>
    … we talked about at AlmaLinux Landing Page WordPress Content Update Solution Tutorial … as well as …
  • user definable form navigation … using …
  • optional dropdown ideas incorporating ideas from Sepia Video via ffmpeg Primer Tutorial … and using …
  • temporary storage places to place output video … and making use of …
  • soft links regarding URLs we talked about at Linux Web Server Soft Link URL Tutorial (saving us having to use ‘data:video/mp4;base64,’ . base64_encode(file_get_contents(trim($endout))) style PHP interventions (which were testing friendships))

… to start down this road towards public facing ffmpeg video editing around here (which we have been hankering for for several years now).

In this first draft of Your Own Ffmpeg Video Changes (via command line ffmpeg) we’re really buttoning down (via not allowing the forward slash character in amongst the user defined ffmpeg command innards) what happens regarding …

  • output video file source location … and …
  • input video file source …

… but who knows what the future holds?!


Previous relevant Ffmpeg Helps iPhone Video to YouTube Tutorial is shown below.

Ffmpeg Helps iPhone Video to YouTube Tutorial

Ffmpeg Helps iPhone Video to YouTube Tutorial

Today we recorded a video looking out from Govetts Leap, Blackheath, here in the Blue Mountains. We captured it via the Camera app on an iPhone via its Video option.

Nineteen seconds long, to share to this MacBook Air we needed AirDrop, the size of it precluding us from using the Photo app’s Mail sharing option.

And that’s where we wanted to use the great ffmpeg in an optimal way to create a video that we could upload to YouTube. In this, we arrived at this excellent link getting us to try …


ffmpeg -i govetts_leap.MOV -c:v libx264 -preset slow -crf 18 -vf scale=out_color_matrix=bt709 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -c:a aac -ar 48000 -ac 2 -b:a 320k -profile:v high -level 4.0 -bf 2 -coder 1 -pix_fmt yuv420p -b:v 10M -threads 4 -cpu-used 0 -r 30 -g 15 -movflags +faststart govetts_leap.mp4

… with success. Checking with this other excellent link, thanks, we were comforted that they would have recommended an output mp4 file format as well, it seems …

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, Operating System, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Ffmpeg User Defined Browsed Video Editing Tutorial

Ffmpeg User Defined Browsed Video Editing Tutorial

Ffmpeg User Defined Browsed Video Editing Tutorial

Today’s work, onto yesterday’s Ffmpeg User Defined Video Editing Tutorial, is to loosen the restrictions regarding “input video file source” we had happening in that “first draft” incarnation of our Ffmpeg User Defined Video Editing web application.

In order to achieve this, we called on a previous Ffmpeg Install and Public Face Tutorial inspired change to our inhouse macos_ffmpeg_convert.php PHP web application, which can serve as our conduit to either/or …

  • browse for a video file off the user local operating system environment … or …
  • path to a web server placed video file … or …
  • URL to a video file

… extra means by which the user can define the “input video file source” that we’re loosening the shackles regarding usage.

To do this, we look for user actions (via PHP writing out Javascript) …

<?php echo ”

var lastpathc='';
var lastopathc='';
var lastvidc='';
var lastvalue='.m4v';
var exactvalue='';
var vext='.mp4';

function lookfor() {
vext='.mp4';
var thisext='';
if (document.getElementById('opath').value != '') {
if (lastopathc != document.getElementById('opath').value && document.getElementById('opath').title != document.getElementById('opath').value) {
lastopathc=document.getElementById('opath').value;
}
}
if (document.getElementById('path').value != '') {
if (lastpathc != document.getElementById('path').value) {
lastpathc=document.getElementById('path').value;
if (lastopathc == ' ') { lastopathc=document.getElementById('opath').value; }
}
}
if (lastopathc.trim() != '') {
thisext=(lastopathc + '.').split('.')[1].split('.')[0].trim();
if (thisext != '') {
document.getElementById('opath').title=lastopathc;
document.getElementById('path').title='video/' + thisext + ';' + lastpathc + lastopathc;
document.getElementById('resultav').value=lastpathc + lastopathc;
lastopathc=' ';
}
}
if (document.getElementById('resultav').value != '') {
if (lastvidc != document.getElementById('resultav').value) {
if ((document.getElementById('path').title + document.getElementById('resultav').value).indexOf('video/') != -1) {
if (document.getElementById('ifbrowse').src.indexOf('=') != -1) {
document.getElementById('myaltin').value=decodeURIComponent(document.getElementById('ifbrowse').src.split('=')[1].split('&')[0].split('#')[0]);
}
if ((document.getElementById('path').title + document.getElementById('resultav').value).indexOf('video/') != -1) {
if (vext.indexOf((document.getElementById('path').title + document.getElementById('resultav').value).split('video/')[1].split(';')[0].split(',')[0]) == -1) {
vext='.' + document.getElementById('resultav').value.split('video/')[1].split(';')[0].split(',')[0];
document.getElementById('myaltin').value=document.getElementById('myaltin').value.split('.')[0] + vext;
document.getElementById('becomes').value=document.getElementById('becomes').value.split('.')[0] + vext;
}
}
lastvidc=document.getElementById('resultav').value;
document.getElementById('resultav').title='rework';
document.getElementById('mysubp').click();
setTimeout(function(){
if (1 == 1) {
document.getElementById('divvid').innerHTML=\"<video id=myinvideo style=width:95%; controls><source id=myinsource type='video/\" + vext.substring(1) + \"' src='\" + document.getElementById('resultav').value + \"'></source></video>\";
} else {
document.getElementById('myinsource').src=document.getElementById('resultav').value;
}
}, 2000);
//setTimeout(function(){
//document.getElementById('resultav').value='';
//}, 20000);
//alert(lastvidc);
setTimeout(lookfor, 23000);
return '';
}
setTimeout(lookfor, 3000);
return '';
}
}
setTimeout(lookfor, 3000);
return '';
}

setTimeout(lookfor, 3000);

“; ?>

… and then arrange the /tmp/ placed temporary video data via …

<?php

if (isset($_POST['browsed']) && isset($_POST['becomes'])) {
$fgccont='';
//file_put_contents('xzm.xzm', '1');
$outtmpfile=str_replace('+',' ',urldecode($_POST['becomes']));
//file_put_contents('xzm2.xzm2', $outtmpfile);
$outext=explode('.', $outtmpfile)[-1 + sizeof(explode('.', $outtmpfile))];
//file_put_contents('xzm3.xzm3', str_replace(' ','+',urldecode($_POST['browsed'])));
if (strpos(('xwq' . $_POST['browsed']), 'xwqdata') !== false) {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), base64_decode(explode(";base64,", str_replace(' ','+',urldecode($_POST['browsed'])))[1]));
} else if (strpos(('xwq' . strtolower($_POST['browsed'])), 'xwqhttps') !== false) {
$fgccont=file_get_contents('http' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),5));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (strpos(('xwq' . strtolower($_POST['browsed'])), 'xwqhttp') !== false) {
$fgccont=file_get_contents('http' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),4));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (strpos(('xwq' . strtolower(str_replace('+',' ',urldecode($_POST['browsed'])))), 'xwq//') !== false) {
$fgccont=file_get_contents('http:' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),0));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (strpos(('xwq' . strtolower(str_replace('+',' ',urldecode($_POST['browsed'])))), 'xwqwww.') !== false) {
$fgccont=file_get_contents('http://' . substr(str_replace('+',' ',urldecode($_POST['browsed'])),0));
if (trim($fgccont) != '') {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), $fgccont);
}
} else if (file_exists(str_replace('+',' ',urldecode($_POST['browsed'])))) {
file_put_contents(str_replace('+',' ',urldecode($_POST['becomes'])), file_get_contents(str_replace('+',' ',urldecode($_POST['browsed']))));
}
//file_put_contents('xzm4.xzm4', explode(";base64,", str_replace(' ','+',urldecode($_POST['browsed'])))[1]);
exit;
}

?>

… all the while being helped out by a tweaked macos_ffmpeg_convert.php works Ffmpeg Converter Tool PHP web application helper to our changed second draft of Your Own Ffmpeg Video Changes, which can be that much more useful in a new way in the AlmaLinux web server environment.


Previous relevant Ffmpeg User Defined Video Editing Tutorial is shown below.

Ffmpeg User Defined Video Editing Tutorial

Ffmpeg User Defined Video Editing Tutorial

Today we’re combining video contents from …

  • yesterday’s Ffmpeg Helps iPhone Video to YouTube Tutorial … with …
  • our newly created public interface to ffmpeg with the “soon to be DNS version of rjmprogramming.com.au … but not yet” AlmaLinux Apache/PHP/MySql web server install we talked about at Ffmpeg Install and Public Face Tutorial … and …
  • IP address redirecting, as needed, ifconfig (via PHP shell_exec and $_SERVER[‘SERVER_ADDR’]) based logic …
    <?php

    $whereplace=shell_exec("ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'");
    if (strpos(($whereplace . ' ' . $_SERVER['SERVER_ADDR']), '65.254.92.213') !== false) {
    $sv='/usr/bin/ffmpeg';
    header('Location: https://65.254.95.247/PHP/tmp_ffmpeg.php'); //$smallpath='https://65.254.95.247/PHP/'; //header('Location: https://65.254.95.247/PHP/tmp_ffmpeg.php');
    exit; //exit;
    }

    ?>
    … we talked about at AlmaLinux Landing Page WordPress Content Update Solution Tutorial … as well as …
  • user definable form navigation … using …
  • optional dropdown ideas incorporating ideas from Sepia Video via ffmpeg Primer Tutorial … and using …
  • temporary storage places to place output video … and making use of …
  • soft links regarding URLs we talked about at Linux Web Server Soft Link URL Tutorial (saving us having to use ‘data:video/mp4;base64,’ . base64_encode(file_get_contents(trim($endout))) style PHP interventions (which were testing friendships))

… to start down this road towards public facing ffmpeg video editing around here (which we have been hankering for for several years now).

In this first draft of Your Own Ffmpeg Video Changes (via command line ffmpeg) we’re really buttoning down (via not allowing the forward slash character in amongst the user defined ffmpeg command innards) what happens regarding …

  • output video file source location … and …
  • input video file source …

… but who knows what the future holds?!


Previous relevant Ffmpeg Helps iPhone Video to YouTube Tutorial is shown below.

Ffmpeg Helps iPhone Video to YouTube Tutorial

Ffmpeg Helps iPhone Video to YouTube Tutorial

Today we recorded a video looking out from Govetts Leap, Blackheath, here in the Blue Mountains. We captured it via the Camera app on an iPhone via its Video option.

Nineteen seconds long, to share to this MacBook Air we needed AirDrop, the size of it precluding us from using the Photo app’s Mail sharing option.

And that’s where we wanted to use the great ffmpeg in an optimal way to create a video that we could upload to YouTube. In this, we arrived at this excellent link getting us to try …


ffmpeg -i govetts_leap.MOV -c:v libx264 -preset slow -crf 18 -vf scale=out_color_matrix=bt709 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -c:a aac -ar 48000 -ac 2 -b:a 320k -profile:v high -level 4.0 -bf 2 -coder 1 -pix_fmt yuv420p -b:v 10M -threads 4 -cpu-used 0 -r 30 -g 15 -movflags +faststart govetts_leap.mp4

… with success. Checking with this other excellent link, thanks, we were comforted that they would have recommended an output mp4 file format as well, it seems …

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

Ffmpeg User Defined Video Editing Tutorial

Ffmpeg User Defined Video Editing Tutorial

Ffmpeg User Defined Video Editing Tutorial

Today we’re combining video contents from …

  • yesterday’s Ffmpeg Helps iPhone Video to YouTube Tutorial … with …
  • our newly created public interface to ffmpeg with the “soon to be DNS version of rjmprogramming.com.au … but not yet” AlmaLinux Apache/PHP/MySql web server install we talked about at Ffmpeg Install and Public Face Tutorial … and …
  • IP address redirecting, as needed, ifconfig (via PHP shell_exec and $_SERVER[‘SERVER_ADDR’]) based logic …
    <?php

    $whereplace=shell_exec("ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'");
    if (strpos(($whereplace . ' ' . $_SERVER['SERVER_ADDR']), '65.254.92.213') !== false) {
    $sv='/usr/bin/ffmpeg';
    header('Location: https://65.254.95.247/PHP/tmp_ffmpeg.php'); //$smallpath='https://65.254.95.247/PHP/'; //header('Location: https://65.254.95.247/PHP/tmp_ffmpeg.php');
    exit; //exit;
    }

    ?>
    … we talked about at AlmaLinux Landing Page WordPress Content Update Solution Tutorial … as well as …
  • user definable form navigation … using …
  • optional dropdown ideas incorporating ideas from Sepia Video via ffmpeg Primer Tutorial … and using …
  • temporary storage places to place output video … and making use of …
  • soft links regarding URLs we talked about at Linux Web Server Soft Link URL Tutorial (saving us having to use ‘data:video/mp4;base64,’ . base64_encode(file_get_contents(trim($endout))) style PHP interventions (which were testing friendships))

… to start down this road towards public facing ffmpeg video editing around here (which we have been hankering for for several years now).

In this first draft of Your Own Ffmpeg Video Changes (via command line ffmpeg) we’re really buttoning down (via not allowing the forward slash character in amongst the user defined ffmpeg command innards) what happens regarding …

  • output video file source location … and …
  • input video file source …

… but who knows what the future holds?!


Previous relevant Ffmpeg Helps iPhone Video to YouTube Tutorial is shown below.

Ffmpeg Helps iPhone Video to YouTube Tutorial

Ffmpeg Helps iPhone Video to YouTube Tutorial

Today we recorded a video looking out from Govetts Leap, Blackheath, here in the Blue Mountains. We captured it via the Camera app on an iPhone via its Video option.

Nineteen seconds long, to share to this MacBook Air we needed AirDrop, the size of it precluding us from using the Photo app’s Mail sharing option.

And that’s where we wanted to use the great ffmpeg in an optimal way to create a video that we could upload to YouTube. In this, we arrived at this excellent link getting us to try …


ffmpeg -i govetts_leap.MOV -c:v libx264 -preset slow -crf 18 -vf scale=out_color_matrix=bt709 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -c:a aac -ar 48000 -ac 2 -b:a 320k -profile:v high -level 4.0 -bf 2 -coder 1 -pix_fmt yuv420p -b:v 10M -threads 4 -cpu-used 0 -r 30 -g 15 -movflags +faststart govetts_leap.mp4

… with success. Checking with this other excellent link, thanks, we were comforted that they would have recommended an output mp4 file format as well, it seems …

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, Software | Tagged , , , , , , , , , , , , , | Leave a comment

Ffmpeg Helps iPhone Video to YouTube Tutorial

Ffmpeg Helps iPhone Video to YouTube Tutorial

Ffmpeg Helps iPhone Video to YouTube Tutorial

Today we recorded a video looking out from Govetts Leap, Blackheath, here in the Blue Mountains. We captured it via the Camera app on an iPhone via its Video option.

Nineteen seconds long, to share to this MacBook Air we needed AirDrop, the size of it precluding us from using the Photo app’s Mail sharing option.

And that’s where we wanted to use the great ffmpeg in an optimal way to create a video that we could upload to YouTube. In this, we arrived at this excellent link getting us to try …


ffmpeg -i govetts_leap.MOV -c:v libx264 -preset slow -crf 18 -vf scale=out_color_matrix=bt709 -color_primaries bt709 -color_trc bt709 -colorspace bt709 -c:a aac -ar 48000 -ac 2 -b:a 320k -profile:v high -level 4.0 -bf 2 -coder 1 -pix_fmt yuv420p -b:v 10M -threads 4 -cpu-used 0 -r 30 -g 15 -movflags +faststart govetts_leap.mp4

… with success. Checking with this other excellent link, thanks, we were comforted that they would have recommended an output mp4 file format as well, it seems …

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

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

AlmaLinux Landing Page WordPress Content Update Solution Tutorial

AlmaLinux Landing Page WordPress Content Update Solution Tutorial

AlmaLinux Landing Page WordPress Content Update Solution Tutorial

As with yesterday’s MySql Watchdog Migration Transition Solution Tutorial, and it’s …

  • crontab and curl “MySql Watchdog” basis … we also, around here, use …
  • crontab and curl “Landing Page Daily Updates Regarding WordPress Blog Posting Content”

… so that going to the RJM Programming Landing Page can glean the latest WordPress Blog content.

During our “pre AlmaLinux” “pre DNS changeover” period, we’ve been doing two lots of WordPress Post “CMS style” textarea blog posting sessions for each daily new blog posting. We’ve got a WordPress Blog with permalinks set to a variant of the blog posting title, and between the two versions …

  • that part of a URL to get to this content remains the same (phew!) but the POST_ID becomes unreliable as a guaranteed thaing … the least worriesome aspect, against …
  • the Landing Page dropdowns for new, but soon to be the DNS IP address need to be populated via WordPress Blog MySql based data, via a tutorial_options.php piece of inhouse PHP which needs to change in a few ways …
    1. references to what used to be “mysql_” style PHP calls now need to be transferred to equivalent “mysqli_” ones (and thanks to php – Replacement for deprecated function mysql_connect – Stack Overflow here, regarding great advice) where, as well as the i change, for all but …
      $link = mysqli_connect($hostname, $username, $password);
      mysqli_num_rows($res)
      mysqli_fetch_row($res)
      mysqli_close($link)
      … references, for our PHP code, which used mysqli_select_db($link, $dbname) and mysqli_query($link,$qry) and mysqli_errno($link) … we needed that extra first argument of the mysqli connection value … changes that reminded us, a tad, of how to go from a CSS Selector to a Javascript DOM by getting rid of _ and just to the right of where that was, capitalize that character, thinking
    2. rethink any $_GET[] or $_POST[] arrangements into $argc (and $argv[1] argument) based logic …
      <?php

      $index = "index";
      if (isset($argc)) {
      if ($argc >= 2) {
      if ($argv[1] != "mobile") {
      $index = $argv[1];
      }
      }
      } else
      if (isset($_GET['index'])) {
      $index = $_GET['index'];
      } else if (isset($_POST['index'])) {
      $index = $_POST['index'];
      }

      ?>
      … so that …

      AlmaLinux CentOS
      cd ~rjmprogr/public_html/PHP; php tutorial_options.php curl http://www.rjmprogramming.com.au/tutorial_options.php
      cd ~rjmprogr/public_html/PHP; php tutorial_options.php mobile curl http://www.rjmprogramming.com.au/tutorial_options.php?mobile=mobile
      cd ~rjmprogr/public_html/PHP; php tutorial_options.php slideshow curl http://www.rjmprogramming.com.au/tutorial_options.php?index=slideshow

      … componentry into “ksh -c “[commands]” within a crontab regime … becomes the go … remember our PHP “Modes of Use” tutorials?

  • similarly but with less bother, even than above, is recent-posts-2.php …
    AlmaLinux CentOS
    cd ~rjmprogr/public_html/PHP; php recent-posts-2.php curl http://www.rjmprogramming.com.au/recent-posts-2.php

… got the functionality going on our AlmaLinux soon to be the DNS IP address environment.


Previous relevant MySql Watchdog Migration Transition Preparations Tutorial is shown below.

MySql Watchdog Migration Transition Preparations Tutorial

MySql Watchdog Migration Transition Preparations Tutorial

When we commented, in AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial

Yes, we’re migrating again (as we were talking about with Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial), though as you read this blog posting, if hot off the press here on 19/7/2024, we’ll not have transferred the DNS over yet, which we’ll outline the reasons for into the future. But, today, we’re excited to outline some steps after …

… it was, mainly, regarding our MySql Watchdog ( korn shell scripting in the Linux Apache/PHP/MySql web server /etc/init.d scripts called via crontab ) that concerned us most. Why (Nala getting distracted, ever since MySql Down Thinking Followup Tutorial … or …)?

Well, understandably our Crazy Domains web hosts were kind enough to …

  • take on the migration … thanks … and not, just blithely …
  • make any “old scripting” assumptions ( ie. we came across the new web server’s /etc/init.d folder as empty (and /etc/rc.d/init.d folder, for your AlmaLinux Apache2 daemon process folder arrangements not empty, but missing our own tailored scripting (and that scripting and our crontabbing used /etc/init.d mentions) … so …) … especially any to do with anything even resembling …
  • crontab … nor, heaven forbid …
  • curl … (the use of which, up to now, we’ve only ever combined with argument URLs that mentioned rjmprogramming.com.au rather than any numerical IP address … hence, our concerns) … scripting being helped out by crontab … that had any personal tailoring ( ie. a crontab -l
    # showed default AlamaLinux arrangements only

This can be very powerful stuff, and you could, during a period before the DNS changeover, if you had a matching crontab situation happening, having two watchdogs on two different IP addresses (only one of which is pointed to proper DNS rjmprogramming.com.au arrangements trying to pick up a MySql service, and though only one would get through picking up the true rjmprogramming.com.au MySql service, the other would, at the very least, be doing superfluous activity because of the way we scripted it. We scripted for …

  • one DNS arrangement for the one IP address related to rjmprogramming.com.au … rather than …
  • one DNS arrangement for the one IP address related to rjmprogramming.com.au and another IP address being readied for a future DNS rearrangement that it will map to … and after that …
  • one DNS arrangement where that new IP address can newly become the DNS for rjmprogramming.com.au and another obsolete (but still having a working crontab happening) IP address awaits a decommission

That is the power, and also the worry, regarding how curl and crontab can be such useful Linux web server tools!

For number 3 scenario, perhaps we can be quick decommissioning, but we imagine we’ll want to have another test period after the DNS changeover. We’ll see. Anyway, on the road towards solutions we’re pretty sure a first step is …

  • before thinking of starting up any “inhouse scripting componentry” crontab schedulings on the new IP address web server …
  • populate our empty /etc/init.d … with …
  • matching script content and permissions and ownership as is (and then, was) happening on the current (but soon to be decommissioned) IP address web server

This transfer of scripts is not suitable for our FileZilla sftp transferring arrangements, and we do not feel like tackling any big shake up of arrangements here.

But, we ended up with a zipping and unzipping methodology that went like …

  • pick a folder that is hidden to the public (for both IP addresses) but that your Linux administration user (in our case “root”) can get to and our FileZilla web server user (in our case “rjmprogr”) can plonk to and from, for us, that being (notice, regarding Apache, no “public_html” mention) … /home/rjmprogr
  • for current, but soon to be decommissioned IP address … ssh login … cd /etc/init.d … zip /home/rjmprogr/etcinitd.zip *
  • use relevant FileZilla on current, but soon to be decommissioned IP address setup to copy this back to your local operating system, ours being macOS …
  • use relevant FileZilla on new, but soon to be the DNS IP address setup to copy this local operating system etcinitd.zip over to /home/rjmprogr
  • for new, but soon to be the DNS IP address … ssh login … cd /etc/init.d … unzip /home/rjmprogr/etcinitd.zip *
  • if happy ( via … ls -l /etc/init.d/* … checking and comparing between IP addresses ), for current, but soon to be decommissioned IP address … ssh login … rm -f /home/rjmprogr/etcinitd.zip # or do this via appropriate FileZilla session
  • if happy ( via … ls -l /etc/init.d/* … checking and comparing between IP addresses ), for new, but soon to be the DNS IP address … ssh login … rm -f /home/rjmprogr/etcinitd.zip # or do this via appropriate FileZilla session

… that we were really happy with.

For a small number of script files, though, an animated GIF presentation we’ve provided (and don’t you just hate it when you only get the knack of it near the end of the job … sheeesh!) you might want to use …

  • open two macOS Terminal windows side by side (and not overlapping) …
  • left one has ssh login to current, but soon to be decommissioned IP address … cd /etc/init.d
  • right one has ssh login to new, but soon to be the DNS IP address … cd /etc/init.d
  • for each ( mainly *.*sh for us ) (korn shell usually for us) script of interest (we’ll call thesc.ksh below) …
    1. # no return key press below …
    2. left % cat thesc.ksh
    3. # you might want to use Terminal app’s Edit -> Copy the highlighted “thesc.ksh” to help (via Terminal app’s Edit -> Paste) with …
    4. right % vi thesc.ksh
    5. at left, as necessary, press Return key
    6. at left highlight from the bottom ( probably “exit” ) up to the top ( probably “#!/bin/ksh” ) and use Terminal app’s Edit -> Copy
    7. at right, as necessary, press Return key
    8. at right, if content already there, use appropriate <escape>999dd command to clear to nothing then …
    9. at right, press “i” key (for Insert) …
    10. at right, use Terminal app’s Edit -> Paste
    11. at right, maybe press <escape>w (to have an interim look) ahead of …
    12. at right, maybe press <escape>wq!
  • attend to any ownership (research chown and chgrp) or file permission (research chmod) mismatches you would tweak to via ls -l /etc/init.d/* … checking and comparing between IP addresses
  • and consider only leaving “inhouse scripting” in /etc/init.d on new, but soon to be the DNS IP address here, for now (and into the future rewrite scripting for /etc/rc.d/init.d reuse)


Previous relevant MySql Down Thinking Followup Tutorial is shown below.

MySql Down Thinking Followup Tutorial

MySql Down Thinking Followup Tutorial

When we discussed Linux Watchdog Primer Tutorial in that very generic fashion below, we were being that … generic. Today we turn to specifics in that regard. On the rjmprogramming.com.au domain we use a …

  • (software) watchdog which checks for the health of the MySql Service, and if not healthy, restore it to health … which is all fine and good from the point of view of the domain rjmprogramming.com.au … but depending on what the user was doing we could …
  • code for intervention within the MySql using piece of software, and writing out the database error to the webpage, and present alternative navigation

… on the understanding with that latter thought, that we put into play today for a WordPress 4.1.1 blog, we realized we needed to intervene in …


[DocumentRoot]/ITblog/wp-includes/functions.php

… in the emboldened code intervention as below …



// Otherwise, be terse.
status_header( 500 );
nocache_headers();
$ubitsare=explode("/", str_replace("/?p=","",$_SERVER['REQUEST_URI']));
if (sizeof($ubitsare) > 2) {
if (strpos(str_replace("-","%20",$ubitsare[2]), "slideshow.htm") === false) {
header("Location: /slideshow.html?title=" . explode("&", str_replace("-","%20",str_replace("/?p=","",$ubitsare[2]))[0]));
exit;
} else {
header( 'Content-Type: text/html; charset=utf-8' );
}
} else {

header( 'Content-Type: text/html; charset=utf-8' );
}
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php _e( 'Database Error' ); ?></title>

</head>
<body>
<h1><?php _e( 'Error establishing a database connection'); ?></h1>
</body>
</html>
<?php
die();
}

… where the redirection to /slideshow.html effectively “Cuts to the Chase” for the gist of that blog posting you never got to, as MySql is currently down.

Notice how specific the actions can be when you write code “dependent” on another software component, as distinct from the “watchdog” approach we often want to be “independent” in its thinking.

Guess this begs the question? How did we work out where to intervene? We just got to folders on the rjmprogramming.com.au web server with the WordPress (Codex) software and went (showing you the one that yielded the nicest result for us) …


pwd // and we are at [DocumentRoot]/ITblog
cd wp-includes
fgrep 'Error establishing a database connection' *.php


Previous relevant Linux Watchdog Primer Tutorial is shown below.

Linux Watchdog Primer Tutorial

Linux Watchdog Primer Tutorial

Do you have a computer operational problem? What the … what is that humanoid on about? Well, is there a computer operation you have to do routinely, to fix an ongoing problem, that relies on your personal intervention that, one day, you’d like to not have to worry about, or better still … you usually intervene, but would like a backup approach should you get sick and can’t do it … here’s where you need Fido a watchdog

… am not recommending a Golden Retriever, unless you want your process licked rather than attended to? (had you forgotten this was a question, Cedric Linux Nala)? …

oh, moi?)

Why is bellybutton fluff blue? But we digress, or at Buckingham Palace one digresses.

Right, back at watchdogs, there are schools of thought …

  1. The process is down for too long and we need to do something about it, because customers are leaving
  2. If you need a watchdog to save your bacon, then (clearly you’re not with it, because the dog’s eaten the bacon and) there is something else fundamentally wrong or something you do not understand, which is what you really should resolve, either way

My view is that, if the underlying process would take years to understand or if it is written in legacy code, I’d go more with the former idea, especially as there is delight in creating a really good watchdog (training one? not so easy) … it can be really hard to do … for this reason cannot give code here really, because there is no “out of the box” that is a responsible approach to advise … you have to study the issue and cut it into its components, unit test the solutions to the components of your watchdog solution, and retest with the interactions of those components. However, this is a coding enthusiast’s view, and is a bit short-sighted, perhaps. In any case, what will save the day is that this decision will probably be made for you by an operations expert, if you work in a large organization.

Some other watchdog considerations should be …

  1. Is the attempt to automate the solution that the watchdog will provide technically possible … may not be?!
  2. We can resolve it with personal intervention … can the watchdog simulate each step of the human intervention? If so, go for that approach if possible.
  3. Be very careful of approaches that involve mouse clicks, as they are quite often relative to too many other environmental issues … try to restrict the watchdog solution to command line/scripting/keyboard ideas … on Windows, AutoHotKey is an excellent recording program of interest (would recommend just using it for keyboard recordings, if using it for a watchdog … by the way, tomorrow (tomorrow arrived today) we do a tutorial showing you how to create an AutoHotKey terminate-and-stay-resident program on Windows).
  4. Have we identified the real intervention points? If not, you might succeed some of the time, but not all the time, and you may cause damage on those times when you have made some assumptions, with your incomplete understanding.

Here is an example. You have an overnight batch process run, and it falls over at a certain point, and you get paged at 3 or 4 (it’s bound to be AM). It has been tentatively decided you might want to create a watchdog … what are some considerations …

  1. What do log files tell me? Find out.
  2. Is it a single thing that is missing that would resolve the problem once and for all? If yes, well, you know not to deviate from this one thing … ignore ideas below.
  3. Of the few problems, is it worth proceeding with the watchdog idea, because the number of separate issues can often cause a factor of ten more complication issue points, and maybe you should stick with human intervention.
  4. Break the watchdog problem into these problem issues as a separate unit-testable piece of scripting code (or whatever your watchdog solution entails) … test each for success … retest for their interaction with each other (ie. that they don’t interfere with each other).

The title of this tutorial mentions Linux but generic thinking like above covers other operating system thought patterns, but there are some Linux (or Unix) tools that are great Linux commands that we should point out … thanks to Hscripts.com and CyberCiti.biz for this …

  1. crontab ( eg. */5 * * * * Username /path/to/command # where /path/to/command gets run by Username every five minutes … arranged via crobtab -e ) … for Windows, equivalent would be Task Schedular in Windows Primer Tutorial
  2. nohup
  3. bg
  4. nice

And here are some of the practicalities of a watchdog …

  1. Where does it run? If at more than one place, consider each place separately. If it runs on more than one computer, then clearly this is important. Does the directory and file permissions allow the watchdog to run, but do not allow other users to misuse it? (Please say yes here.) A generic thing about crontab or nohup (or Windows start) scripting arrangements are that you should not assume the environments of these processes is the same as your current running command line process … you should write as if you have just logged on and have done nothing … so just about the first decision of the script is to “cd” itself to the proper place where it was designed to run.
  2. Which user(s) (on whichever computer(s)) can run it?
  3. When does it run? If the solution is uncomplicated enough, maybe you can use a pre-emptive approach. For example, you know the problem is to do with a file missing when a non-critical process fails but later on that file is looked for, then why not pre-emptively get the watchdog to create that file (with default data) ahead of the process run crash point time.
  4. As part of the question above, does one subprocess need to end before another starts? If yes, you need to intervene in such a way that that process architecture remains, and you need to work out an independent way for your independent watchdog to step in, at the correct time, and take over the same task, as required. But if it gets to this, don’t you understand the underlying process well enough to have a crack at doing the “real” solution (for all time)? Have a think, now, and keep checking in on the issue?
  5. You need to log the workings of the watchdog both for information and for further research which might help in achieving a “real” solution (without the watchdog) further down the track.

So why was this posting called a tutorial? Well, there’s some homework. You see there are these Daleks, and we sort of need to know when they’re going to invade Earth again, and Dr Who is not always available, so, was wondering, if it wouldn’t be too inconvenient … if you wouldn’t mind writing that watchdog to detect a Dalek invasion and shoo them off … 6 hours … okay?

Woofsky!

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, Operating System, Software, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

MySql Watchdog Migration Transition Solution Tutorial

MySql Watchdog Migration Transition Solution Tutorial

MySql Watchdog Migration Transition Solution Tutorial

Onto yesterday’s MySql Watchdog Migration Transition Preparations Tutorial, yes, with Korn Shell scripting, thanks to the advice from How to use nslookup in bash to verify is DNS is configured properly? and bash – How to get the primary IP address of the local machine on Linux and OS X? – Stack Overflow


#!/bin/ksh
# will_the_real_rjmprogramming_com_au_holler.ksh

nsl="`nslookup rjmprogramming.com.au`";
myip="`ifconfig | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | grep -Eo '([0-9]*\.){3}[0-9]*' | grep -v '127.0.0.1'`";
if [ "`echo ${nsl} | grep -c ${myip}`" != "0" ]; then
if [ -d '/home/rjmprogr/public_html/wordpress/' -a "$1" = "doit" ]; then
echo y > /home/rjmprogr/public_html/wordpress/mysql_needs.attention
chmod 777 /home/rjmprogr/public_html/wordpress/mysql_needs.attention

else
echo "yes";
fi
exit;
fi
if [ -d '/home/rjmprogr/public_html/wordpress/' -a "$1" = "doit" ]; then
echo "";
else
echo "no";
fi
exit;

… we can now “play dead” (by taking those blue codelines, which also appear in the MySql Watchdog, and now, instead, have …


if [ "2" != "4" ] ; then
ksh /etc/init.d/will_the_real_rjmprogramming_com_au_holler.ksh doit
else
echo y > /home/rjmprogr/public_html/wordpress/mysql_needs.attention
chmod 777 /home/rjmprogr/public_html/wordpress/mysql_needs.attention

fi

…) regarding web servers whose IP address do not match the DNS looked up for rjmprogramming.com.au as a domain, with that “attention seeking” /home/rjmprogr/public_html/wordpress/mysql_needs.attention file creation that our MySql Watchdog works off as the basis to swing into action … more reliable than …

Nala! Would you please get off the bed and attend to MySql having just fallen over … pretty pleeeaaaassseee!


Previous relevant MySql Watchdog Migration Transition Preparations Tutorial is shown below.

MySql Watchdog Migration Transition Preparations Tutorial

MySql Watchdog Migration Transition Preparations Tutorial

When we commented, in AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial

Yes, we’re migrating again (as we were talking about with Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial), though as you read this blog posting, if hot off the press here on 19/7/2024, we’ll not have transferred the DNS over yet, which we’ll outline the reasons for into the future. But, today, we’re excited to outline some steps after …

… it was, mainly, regarding our MySql Watchdog ( korn shell scripting in the Linux Apache/PHP/MySql web server /etc/init.d scripts called via crontab ) that concerned us most. Why (Nala getting distracted, ever since MySql Down Thinking Followup Tutorial … or …)?

Well, understandably our Crazy Domains web hosts were kind enough to …

  • take on the migration … thanks … and not, just blithely …
  • make any “old scripting” assumptions ( ie. we came across the new web server’s /etc/init.d folder as empty (and /etc/rc.d/init.d folder, for your AlmaLinux Apache2 daemon process folder arrangements not empty, but missing our own tailored scripting (and that scripting and our crontabbing used /etc/init.d mentions) … so …) … especially any to do with anything even resembling …
  • crontab … nor, heaven forbid …
  • curl … (the use of which, up to now, we’ve only ever combined with argument URLs that mentioned rjmprogramming.com.au rather than any numerical IP address … hence, our concerns) … scripting being helped out by crontab … that had any personal tailoring ( ie. a crontab -l
    # showed default AlamaLinux arrangements only

This can be very powerful stuff, and you could, during a period before the DNS changeover, if you had a matching crontab situation happening, having two watchdogs on two different IP addresses (only one of which is pointed to proper DNS rjmprogramming.com.au arrangements trying to pick up a MySql service, and though only one would get through picking up the true rjmprogramming.com.au MySql service, the other would, at the very least, be doing superfluous activity because of the way we scripted it. We scripted for …

  • one DNS arrangement for the one IP address related to rjmprogramming.com.au … rather than …
  • one DNS arrangement for the one IP address related to rjmprogramming.com.au and another IP address being readied for a future DNS rearrangement that it will map to … and after that …
  • one DNS arrangement where that new IP address can newly become the DNS for rjmprogramming.com.au and another obsolete (but still having a working crontab happening) IP address awaits a decommission

That is the power, and also the worry, regarding how curl and crontab can be such useful Linux web server tools!

For number 3 scenario, perhaps we can be quick decommissioning, but we imagine we’ll want to have another test period after the DNS changeover. We’ll see. Anyway, on the road towards solutions we’re pretty sure a first step is …

  • before thinking of starting up any “inhouse scripting componentry” crontab schedulings on the new IP address web server …
  • populate our empty /etc/init.d … with …
  • matching script content and permissions and ownership as is (and then, was) happening on the current (but soon to be decommissioned) IP address web server

This transfer of scripts is not suitable for our FileZilla sftp transferring arrangements, and we do not feel like tackling any big shake up of arrangements here.

But, we ended up with a zipping and unzipping methodology that went like …

  • pick a folder that is hidden to the public (for both IP addresses) but that your Linux administration user (in our case “root”) can get to and our FileZilla web server user (in our case “rjmprogr”) can plonk to and from, for us, that being (notice, regarding Apache, no “public_html” mention) … /home/rjmprogr
  • for current, but soon to be decommissioned IP address … ssh login … cd /etc/init.d … zip /home/rjmprogr/etcinitd.zip *
  • use relevant FileZilla on current, but soon to be decommissioned IP address setup to copy this back to your local operating system, ours being macOS …
  • use relevant FileZilla on new, but soon to be the DNS IP address setup to copy this local operating system etcinitd.zip over to /home/rjmprogr
  • for new, but soon to be the DNS IP address … ssh login … cd /etc/init.d … unzip /home/rjmprogr/etcinitd.zip *
  • if happy ( via … ls -l /etc/init.d/* … checking and comparing between IP addresses ), for current, but soon to be decommissioned IP address … ssh login … rm -f /home/rjmprogr/etcinitd.zip # or do this via appropriate FileZilla session
  • if happy ( via … ls -l /etc/init.d/* … checking and comparing between IP addresses ), for new, but soon to be the DNS IP address … ssh login … rm -f /home/rjmprogr/etcinitd.zip # or do this via appropriate FileZilla session

… that we were really happy with.

For a small number of script files, though, an animated GIF presentation we’ve provided (and don’t you just hate it when you only get the knack of it near the end of the job … sheeesh!) you might want to use …

  • open two macOS Terminal windows side by side (and not overlapping) …
  • left one has ssh login to current, but soon to be decommissioned IP address … cd /etc/init.d
  • right one has ssh login to new, but soon to be the DNS IP address … cd /etc/init.d
  • for each ( mainly *.*sh for us ) (korn shell usually for us) script of interest (we’ll call thesc.ksh below) …
    1. # no return key press below …
    2. left % cat thesc.ksh
    3. # you might want to use Terminal app’s Edit -> Copy the highlighted “thesc.ksh” to help (via Terminal app’s Edit -> Paste) with …
    4. right % vi thesc.ksh
    5. at left, as necessary, press Return key
    6. at left highlight from the bottom ( probably “exit” ) up to the top ( probably “#!/bin/ksh” ) and use Terminal app’s Edit -> Copy
    7. at right, as necessary, press Return key
    8. at right, if content already there, use appropriate <escape>999dd command to clear to nothing then …
    9. at right, press “i” key (for Insert) …
    10. at right, use Terminal app’s Edit -> Paste
    11. at right, maybe press <escape>w (to have an interim look) ahead of …
    12. at right, maybe press <escape>wq!
  • attend to any ownership (research chown and chgrp) or file permission (research chmod) mismatches you would tweak to via ls -l /etc/init.d/* … checking and comparing between IP addresses
  • and consider only leaving “inhouse scripting” in /etc/init.d on new, but soon to be the DNS IP address here, for now (and into the future rewrite scripting for /etc/rc.d/init.d reuse)


Previous relevant MySql Down Thinking Followup Tutorial is shown below.

MySql Down Thinking Followup Tutorial

MySql Down Thinking Followup Tutorial

When we discussed Linux Watchdog Primer Tutorial in that very generic fashion below, we were being that … generic. Today we turn to specifics in that regard. On the rjmprogramming.com.au domain we use a …

  • (software) watchdog which checks for the health of the MySql Service, and if not healthy, restore it to health … which is all fine and good from the point of view of the domain rjmprogramming.com.au … but depending on what the user was doing we could …
  • code for intervention within the MySql using piece of software, and writing out the database error to the webpage, and present alternative navigation

… on the understanding with that latter thought, that we put into play today for a WordPress 4.1.1 blog, we realized we needed to intervene in …


[DocumentRoot]/ITblog/wp-includes/functions.php

… in the emboldened code intervention as below …



// Otherwise, be terse.
status_header( 500 );
nocache_headers();
$ubitsare=explode("/", str_replace("/?p=","",$_SERVER['REQUEST_URI']));
if (sizeof($ubitsare) > 2) {
if (strpos(str_replace("-","%20",$ubitsare[2]), "slideshow.htm") === false) {
header("Location: /slideshow.html?title=" . explode("&", str_replace("-","%20",str_replace("/?p=","",$ubitsare[2]))[0]));
exit;
} else {
header( 'Content-Type: text/html; charset=utf-8' );
}
} else {

header( 'Content-Type: text/html; charset=utf-8' );
}
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php _e( 'Database Error' ); ?></title>

</head>
<body>
<h1><?php _e( 'Error establishing a database connection'); ?></h1>
</body>
</html>
<?php
die();
}

… where the redirection to /slideshow.html effectively “Cuts to the Chase” for the gist of that blog posting you never got to, as MySql is currently down.

Notice how specific the actions can be when you write code “dependent” on another software component, as distinct from the “watchdog” approach we often want to be “independent” in its thinking.

Guess this begs the question? How did we work out where to intervene? We just got to folders on the rjmprogramming.com.au web server with the WordPress (Codex) software and went (showing you the one that yielded the nicest result for us) …


pwd // and we are at [DocumentRoot]/ITblog
cd wp-includes
fgrep 'Error establishing a database connection' *.php


Previous relevant Linux Watchdog Primer Tutorial is shown below.

Linux Watchdog Primer Tutorial

Linux Watchdog Primer Tutorial

Do you have a computer operational problem? What the … what is that humanoid on about? Well, is there a computer operation you have to do routinely, to fix an ongoing problem, that relies on your personal intervention that, one day, you’d like to not have to worry about, or better still … you usually intervene, but would like a backup approach should you get sick and can’t do it … here’s where you need Fido a watchdog

… am not recommending a Golden Retriever, unless you want your process licked rather than attended to? (had you forgotten this was a question, Cedric Linux Nala)? …

oh, moi?)

Why is bellybutton fluff blue? But we digress, or at Buckingham Palace one digresses.

Right, back at watchdogs, there are schools of thought …

  1. The process is down for too long and we need to do something about it, because customers are leaving
  2. If you need a watchdog to save your bacon, then (clearly you’re not with it, because the dog’s eaten the bacon and) there is something else fundamentally wrong or something you do not understand, which is what you really should resolve, either way

My view is that, if the underlying process would take years to understand or if it is written in legacy code, I’d go more with the former idea, especially as there is delight in creating a really good watchdog (training one? not so easy) … it can be really hard to do … for this reason cannot give code here really, because there is no “out of the box” that is a responsible approach to advise … you have to study the issue and cut it into its components, unit test the solutions to the components of your watchdog solution, and retest with the interactions of those components. However, this is a coding enthusiast’s view, and is a bit short-sighted, perhaps. In any case, what will save the day is that this decision will probably be made for you by an operations expert, if you work in a large organization.

Some other watchdog considerations should be …

  1. Is the attempt to automate the solution that the watchdog will provide technically possible … may not be?!
  2. We can resolve it with personal intervention … can the watchdog simulate each step of the human intervention? If so, go for that approach if possible.
  3. Be very careful of approaches that involve mouse clicks, as they are quite often relative to too many other environmental issues … try to restrict the watchdog solution to command line/scripting/keyboard ideas … on Windows, AutoHotKey is an excellent recording program of interest (would recommend just using it for keyboard recordings, if using it for a watchdog … by the way, tomorrow (tomorrow arrived today) we do a tutorial showing you how to create an AutoHotKey terminate-and-stay-resident program on Windows).
  4. Have we identified the real intervention points? If not, you might succeed some of the time, but not all the time, and you may cause damage on those times when you have made some assumptions, with your incomplete understanding.

Here is an example. You have an overnight batch process run, and it falls over at a certain point, and you get paged at 3 or 4 (it’s bound to be AM). It has been tentatively decided you might want to create a watchdog … what are some considerations …

  1. What do log files tell me? Find out.
  2. Is it a single thing that is missing that would resolve the problem once and for all? If yes, well, you know not to deviate from this one thing … ignore ideas below.
  3. Of the few problems, is it worth proceeding with the watchdog idea, because the number of separate issues can often cause a factor of ten more complication issue points, and maybe you should stick with human intervention.
  4. Break the watchdog problem into these problem issues as a separate unit-testable piece of scripting code (or whatever your watchdog solution entails) … test each for success … retest for their interaction with each other (ie. that they don’t interfere with each other).

The title of this tutorial mentions Linux but generic thinking like above covers other operating system thought patterns, but there are some Linux (or Unix) tools that are great Linux commands that we should point out … thanks to Hscripts.com and CyberCiti.biz for this …

  1. crontab ( eg. */5 * * * * Username /path/to/command # where /path/to/command gets run by Username every five minutes … arranged via crobtab -e ) … for Windows, equivalent would be Task Schedular in Windows Primer Tutorial
  2. nohup
  3. bg
  4. nice

And here are some of the practicalities of a watchdog …

  1. Where does it run? If at more than one place, consider each place separately. If it runs on more than one computer, then clearly this is important. Does the directory and file permissions allow the watchdog to run, but do not allow other users to misuse it? (Please say yes here.) A generic thing about crontab or nohup (or Windows start) scripting arrangements are that you should not assume the environments of these processes is the same as your current running command line process … you should write as if you have just logged on and have done nothing … so just about the first decision of the script is to “cd” itself to the proper place where it was designed to run.
  2. Which user(s) (on whichever computer(s)) can run it?
  3. When does it run? If the solution is uncomplicated enough, maybe you can use a pre-emptive approach. For example, you know the problem is to do with a file missing when a non-critical process fails but later on that file is looked for, then why not pre-emptively get the watchdog to create that file (with default data) ahead of the process run crash point time.
  4. As part of the question above, does one subprocess need to end before another starts? If yes, you need to intervene in such a way that that process architecture remains, and you need to work out an independent way for your independent watchdog to step in, at the correct time, and take over the same task, as required. But if it gets to this, don’t you understand the underlying process well enough to have a crack at doing the “real” solution (for all time)? Have a think, now, and keep checking in on the issue?
  5. You need to log the workings of the watchdog both for information and for further research which might help in achieving a “real” solution (without the watchdog) further down the track.

So why was this posting called a tutorial? Well, there’s some homework. You see there are these Daleks, and we sort of need to know when they’re going to invade Earth again, and Dr Who is not always available, so, was wondering, if it wouldn’t be too inconvenient … if you wouldn’t mind writing that watchdog to detect a Dalek invasion and shoo them off … 6 hours … okay?

Woofsky!

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, Operating System, Software, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

MySql Watchdog Migration Transition Preparations Tutorial

MySql Watchdog Migration Transition Preparations Tutorial

MySql Watchdog Migration Transition Preparations Tutorial

When we commented, in AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial

Yes, we’re migrating again (as we were talking about with Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial), though as you read this blog posting, if hot off the press here on 19/7/2024, we’ll not have transferred the DNS over yet, which we’ll outline the reasons for into the future. But, today, we’re excited to outline some steps after …

… it was, mainly, regarding our MySql Watchdog ( korn shell scripting in the Linux Apache/PHP/MySql web server /etc/init.d scripts called via crontab ) that concerned us most. Why (Nala getting distracted, ever since MySql Down Thinking Followup Tutorial … or …)?

Well, understandably our Crazy Domains web hosts were kind enough to …

  • take on the migration … thanks … and not, just blithely …
  • make any “old scripting” assumptions ( ie. we came across the new web server’s /etc/init.d folder as empty (and /etc/rc.d/init.d folder, for your AlmaLinux Apache2 daemon process folder arrangements not empty, but missing our own tailored scripting (and that scripting and our crontabbing used /etc/init.d mentions) … so …) … especially any to do with anything even resembling …
  • crontab … nor, heaven forbid …
  • curl … (the use of which, up to now, we’ve only ever combined with argument URLs that mentioned rjmprogramming.com.au rather than any numerical IP address … hence, our concerns) … scripting being helped out by crontab … that had any personal tailoring ( ie. a crontab -l
    # showed default AlamaLinux arrangements only

This can be very powerful stuff, and you could, during a period before the DNS changeover, if you had a matching crontab situation happening, having two watchdogs on two different IP addresses (only one of which is pointed to proper DNS rjmprogramming.com.au arrangements trying to pick up a MySql service, and though only one would get through picking up the true rjmprogramming.com.au MySql service, the other would, at the very least, be doing superfluous activity because of the way we scripted it. We scripted for …

  • one DNS arrangement for the one IP address related to rjmprogramming.com.au … rather than …
  • one DNS arrangement for the one IP address related to rjmprogramming.com.au and another IP address being readied for a future DNS rearrangement that it will map to … and after that …
  • one DNS arrangement where that new IP address can newly become the DNS for rjmprogramming.com.au and another obsolete (but still having a working crontab happening) IP address awaits a decommission

That is the power, and also the worry, regarding how curl and crontab can be such useful Linux web server tools!

For number 3 scenario, perhaps we can be quick decommissioning, but we imagine we’ll want to have another test period after the DNS changeover. We’ll see. Anyway, on the road towards solutions we’re pretty sure a first step is …

  • before thinking of starting up any “inhouse scripting componentry” crontab schedulings on the new IP address web server …
  • populate our empty /etc/init.d … with …
  • matching script content and permissions and ownership as is (and then, was) happening on the current (but soon to be decommissioned) IP address web server

This transfer of scripts is not suitable for our FileZilla sftp transferring arrangements, and we do not feel like tackling any big shake up of arrangements here.

But, we ended up with a zipping and unzipping methodology that went like …

  • pick a folder that is hidden to the public (for both IP addresses) but that your Linux administration user (in our case “root”) can get to and our FileZilla web server user (in our case “rjmprogr”) can plonk to and from, for us, that being (notice, regarding Apache, no “public_html” mention) … /home/rjmprogr
  • for current, but soon to be decommissioned IP address … ssh login … cd /etc/init.d … zip /home/rjmprogr/etcinitd.zip *
  • use relevant FileZilla on current, but soon to be decommissioned IP address setup to copy this back to your local operating system, ours being macOS …
  • use relevant FileZilla on new, but soon to be the DNS IP address setup to copy this local operating system etcinitd.zip over to /home/rjmprogr
  • for new, but soon to be the DNS IP address … ssh login … cd /etc/init.d … unzip /home/rjmprogr/etcinitd.zip *
  • if happy ( via … ls -l /etc/init.d/* … checking and comparing between IP addresses ), for current, but soon to be decommissioned IP address … ssh login … rm -f /home/rjmprogr/etcinitd.zip # or do this via appropriate FileZilla session
  • if happy ( via … ls -l /etc/init.d/* … checking and comparing between IP addresses ), for new, but soon to be the DNS IP address … ssh login … rm -f /home/rjmprogr/etcinitd.zip # or do this via appropriate FileZilla session

… that we were really happy with.

For a small number of script files, though, an animated GIF presentation we’ve provided (and don’t you just hate it when you only get the knack of it near the end of the job … sheeesh!) you might want to use …

  • open two macOS Terminal windows side by side (and not overlapping) …
  • left one has ssh login to current, but soon to be decommissioned IP address … cd /etc/init.d
  • right one has ssh login to new, but soon to be the DNS IP address … cd /etc/init.d
  • for each ( mainly *.*sh for us ) (korn shell usually for us) script of interest (we’ll call thesc.ksh below) …
    1. # no return key press below …
    2. left % cat thesc.ksh
    3. # you might want to use Terminal app’s Edit -> Copy the highlighted “thesc.ksh” to help (via Terminal app’s Edit -> Paste) with …
    4. right % vi thesc.ksh
    5. at left, as necessary, press Return key
    6. at left highlight from the bottom ( probably “exit” ) up to the top ( probably “#!/bin/ksh” ) and use Terminal app’s Edit -> Copy
    7. at right, as necessary, press Return key
    8. at right, if content already there, use appropriate <escape>999dd command to clear to nothing then …
    9. at right, press “i” key (for Insert) …
    10. at right, use Terminal app’s Edit -> Paste
    11. at right, maybe press <escape>w (to have an interim look) ahead of …
    12. at right, maybe press <escape>wq!
  • attend to any ownership (research chown and chgrp) or file permission (research chmod) mismatches you would tweak to via ls -l /etc/init.d/* … checking and comparing between IP addresses
  • and consider only leaving “inhouse scripting” in /etc/init.d on new, but soon to be the DNS IP address here, for now (and into the future rewrite scripting for /etc/rc.d/init.d reuse)


Previous relevant MySql Down Thinking Followup Tutorial is shown below.

MySql Down Thinking Followup Tutorial

MySql Down Thinking Followup Tutorial

When we discussed Linux Watchdog Primer Tutorial in that very generic fashion below, we were being that … generic. Today we turn to specifics in that regard. On the rjmprogramming.com.au domain we use a …

  • (software) watchdog which checks for the health of the MySql Service, and if not healthy, restore it to health … which is all fine and good from the point of view of the domain rjmprogramming.com.au … but depending on what the user was doing we could …
  • code for intervention within the MySql using piece of software, and writing out the database error to the webpage, and present alternative navigation

… on the understanding with that latter thought, that we put into play today for a WordPress 4.1.1 blog, we realized we needed to intervene in …


[DocumentRoot]/ITblog/wp-includes/functions.php

… in the emboldened code intervention as below …



// Otherwise, be terse.
status_header( 500 );
nocache_headers();
$ubitsare=explode("/", str_replace("/?p=","",$_SERVER['REQUEST_URI']));
if (sizeof($ubitsare) > 2) {
if (strpos(str_replace("-","%20",$ubitsare[2]), "slideshow.htm") === false) {
header("Location: /slideshow.html?title=" . explode("&", str_replace("-","%20",str_replace("/?p=","",$ubitsare[2]))[0]));
exit;
} else {
header( 'Content-Type: text/html; charset=utf-8' );
}
} else {

header( 'Content-Type: text/html; charset=utf-8' );
}
?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php _e( 'Database Error' ); ?></title>

</head>
<body>
<h1><?php _e( 'Error establishing a database connection'); ?></h1>
</body>
</html>
<?php
die();
}

… where the redirection to /slideshow.html effectively “Cuts to the Chase” for the gist of that blog posting you never got to, as MySql is currently down.

Notice how specific the actions can be when you write code “dependent” on another software component, as distinct from the “watchdog” approach we often want to be “independent” in its thinking.

Guess this begs the question? How did we work out where to intervene? We just got to folders on the rjmprogramming.com.au web server with the WordPress (Codex) software and went (showing you the one that yielded the nicest result for us) …


pwd // and we are at [DocumentRoot]/ITblog
cd wp-includes
fgrep 'Error establishing a database connection' *.php


Previous relevant Linux Watchdog Primer Tutorial is shown below.

Linux Watchdog Primer Tutorial

Linux Watchdog Primer Tutorial

Do you have a computer operational problem? What the … what is that humanoid on about? Well, is there a computer operation you have to do routinely, to fix an ongoing problem, that relies on your personal intervention that, one day, you’d like to not have to worry about, or better still … you usually intervene, but would like a backup approach should you get sick and can’t do it … here’s where you need Fido a watchdog

… am not recommending a Golden Retriever, unless you want your process licked rather than attended to? (had you forgotten this was a question, Cedric Linux Nala)? …

oh, moi?)

Why is bellybutton fluff blue? But we digress, or at Buckingham Palace one digresses.

Right, back at watchdogs, there are schools of thought …

  1. The process is down for too long and we need to do something about it, because customers are leaving
  2. If you need a watchdog to save your bacon, then (clearly you’re not with it, because the dog’s eaten the bacon and) there is something else fundamentally wrong or something you do not understand, which is what you really should resolve, either way

My view is that, if the underlying process would take years to understand or if it is written in legacy code, I’d go more with the former idea, especially as there is delight in creating a really good watchdog (training one? not so easy) … it can be really hard to do … for this reason cannot give code here really, because there is no “out of the box” that is a responsible approach to advise … you have to study the issue and cut it into its components, unit test the solutions to the components of your watchdog solution, and retest with the interactions of those components. However, this is a coding enthusiast’s view, and is a bit short-sighted, perhaps. In any case, what will save the day is that this decision will probably be made for you by an operations expert, if you work in a large organization.

Some other watchdog considerations should be …

  1. Is the attempt to automate the solution that the watchdog will provide technically possible … may not be?!
  2. We can resolve it with personal intervention … can the watchdog simulate each step of the human intervention? If so, go for that approach if possible.
  3. Be very careful of approaches that involve mouse clicks, as they are quite often relative to too many other environmental issues … try to restrict the watchdog solution to command line/scripting/keyboard ideas … on Windows, AutoHotKey is an excellent recording program of interest (would recommend just using it for keyboard recordings, if using it for a watchdog … by the way, tomorrow (tomorrow arrived today) we do a tutorial showing you how to create an AutoHotKey terminate-and-stay-resident program on Windows).
  4. Have we identified the real intervention points? If not, you might succeed some of the time, but not all the time, and you may cause damage on those times when you have made some assumptions, with your incomplete understanding.

Here is an example. You have an overnight batch process run, and it falls over at a certain point, and you get paged at 3 or 4 (it’s bound to be AM). It has been tentatively decided you might want to create a watchdog … what are some considerations …

  1. What do log files tell me? Find out.
  2. Is it a single thing that is missing that would resolve the problem once and for all? If yes, well, you know not to deviate from this one thing … ignore ideas below.
  3. Of the few problems, is it worth proceeding with the watchdog idea, because the number of separate issues can often cause a factor of ten more complication issue points, and maybe you should stick with human intervention.
  4. Break the watchdog problem into these problem issues as a separate unit-testable piece of scripting code (or whatever your watchdog solution entails) … test each for success … retest for their interaction with each other (ie. that they don’t interfere with each other).

The title of this tutorial mentions Linux but generic thinking like above covers other operating system thought patterns, but there are some Linux (or Unix) tools that are great Linux commands that we should point out … thanks to Hscripts.com and CyberCiti.biz for this …

  1. crontab ( eg. */5 * * * * Username /path/to/command # where /path/to/command gets run by Username every five minutes … arranged via crobtab -e ) … for Windows, equivalent would be Task Schedular in Windows Primer Tutorial
  2. nohup
  3. bg
  4. nice

And here are some of the practicalities of a watchdog …

  1. Where does it run? If at more than one place, consider each place separately. If it runs on more than one computer, then clearly this is important. Does the directory and file permissions allow the watchdog to run, but do not allow other users to misuse it? (Please say yes here.) A generic thing about crontab or nohup (or Windows start) scripting arrangements are that you should not assume the environments of these processes is the same as your current running command line process … you should write as if you have just logged on and have done nothing … so just about the first decision of the script is to “cd” itself to the proper place where it was designed to run.
  2. Which user(s) (on whichever computer(s)) can run it?
  3. When does it run? If the solution is uncomplicated enough, maybe you can use a pre-emptive approach. For example, you know the problem is to do with a file missing when a non-critical process fails but later on that file is looked for, then why not pre-emptively get the watchdog to create that file (with default data) ahead of the process run crash point time.
  4. As part of the question above, does one subprocess need to end before another starts? If yes, you need to intervene in such a way that that process architecture remains, and you need to work out an independent way for your independent watchdog to step in, at the correct time, and take over the same task, as required. But if it gets to this, don’t you understand the underlying process well enough to have a crack at doing the “real” solution (for all time)? Have a think, now, and keep checking in on the issue?
  5. You need to log the workings of the watchdog both for information and for further research which might help in achieving a “real” solution (without the watchdog) further down the track.

So why was this posting called a tutorial? Well, there’s some homework. You see there are these Daleks, and we sort of need to know when they’re going to invade Earth again, and Dr Who is not always available, so, was wondering, if it wouldn’t be too inconvenient … if you wouldn’t mind writing that watchdog to detect a Dalek invasion and shoo them off … 6 hours … okay?

Woofsky!

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, Operating System, Software, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Javascript Map Array Destructuring Tutorial

Javascript Map Array Destructuiring Tutorial

Javascript Map Array Destructuring Tutorial

Structured data makes lots of programmers happy, in a similar way the “order” in “law and order” makes people happy. But, often, complexity works well with storage, but in analyzing what the data means, the programmer wants to break it back down into simpler forms.

We came across this excellent link from W3schools, thanks, regarding this, and while we had data at the ready to do with our current Javascript Array and Map project from yesterday’s Javascript Map Array Aggregates Tutorial, we decided to try out, or let the user try out, some of these Destructuring concepts and breakdowns for themselves, with the …

  • array … and Javascript …
  • Map object … data

… they build up, perhaps via CSV input data, accessed via double clicks of “and” … yes … “and” … and …


function destructuringfun(evt) {
evt.stopPropagation();
var kcommands=[];
var answ=null, xinterim='', zone=1, zinterim='', ioff=0, joff=1, soff=',';
var arestmore='', fruitymap;
var abstr='', iab=0, othera="a", lastchar="", prefixer="";
var ione=0, itwo=0, iones=[];
var dfun=prompt('Destructuring ( thanks to https://www.w3schools.com/js/js_destructuring.asp ) ideas with arrays and maps behind this data. Enter prefixing suggestion text (all uppercase for quantity based), then your relevant numericals ... via examples presented ...' + String.fromCharCode(10) + 'Rest after 3' + String.fromCharCode(10) + 'Rest after 1,2' + String.fromCharCode(10) + 'Rest after 1,,2' + String.fromCharCode(10) + 'Key via 1,2' + String.fromCharCode(10), '');
if (dfun == null) { dfun=''; }
if (dfun.toLowerCase().indexOf('key via ') == 0) {
iones=(dfun.toLowerCase() + ' ').split('key via ')[1].split(',');
if (eval('' + iones.length) < 1) {
iones[0]='1';
iones.push('' + fruitymap.length);
} else if (eval('' + iones.length) <= 1) {
if (iones[0].trim() == '') {
iones[0]='1';
iones.push('' + fruity.length);
} else {
iones.push('' + eval(eval('' + fruity.length) - eval('' + iones[0])));
iones[1]=eval(eval('' + iones[0]) + eval('' + iones[1]));
}
} else {
joff=1;
while (('' + iones[joff]).trim() == '') { joff++; ioff++; soff+='' + eval(eval('' + ioff) + eval('' + iones[0])) + ','; }
iones[joff]=eval(eval('' + iones[0]) - 1 + ioff + eval('' + iones[joff]));
}

fruitymap=new Map();
for (iab=1; iab<=fruity.length; iab++) {
if (soff.indexOf(',' + iab + ',') == -1) {
if (dfun.indexOf('KEY VIA ') == 0) {
if (iab >= eval('' + iones[0]) && iab <= eval('' + iones[joff])) {
fruitymap.set('quantity' + eval(0 + iab),fruity[-1 + iab].quantity);
}
} else {
if (iab >= eval('' + iones[0]) && iab <= eval('' + iones[joff])) {
fruitymap.set('name' + eval(0 + iab),fruity[-1 + iab].name);
}
}
}
}

kcommands=['gtext=""; /' + '/ using representative Javascript Map object data below '];
kcommands.push('for (var [gkey, gvalue] of fruitymap) { gtext+=gkey + " is " + gvalue + String.fromCharCode(10); }');

eval(kcommands[0]);
eval(kcommands[1]);
answ=prompt(kcommands[0] + String.fromCharCode(10) + kcommands[1] + String.fromCharCode(10) + ' ... got us to ... ' + String.fromCharCode(10) + String.fromCharCode(10) + 'gtext="' + gtext + '"', gtext);

} else if (dfun.toLowerCase().indexOf('rest after ') == 0) {
fruitything=[];
for (iab=0; iab<fruity.length; iab++) {
if (dfun.indexOf('REST AFTER ') == 0) {
fruitything.push(fruity[iab].quantity);
} else {
fruitything.push(fruity[iab].name);
}
}
ione=(dfun.toLowerCase() + ' ').split('rest after ')[1].split(',')[0].split(' ')[0];
iones=(dfun.toLowerCase() + ' ').split('rest after ')[1].split(',');
abstr='';
for (iab=0; iab<ione; iab++) {
abstr+=othera + ',';
if (othera.slice(-1) == 'z') { prefixer=othera; othera+='a'; } else { lastchar=String.fromCharCode(1 + othera.slice(-1).charCodeAt(0)); othera=prefixer + lastchar; }
}
//alert("var [" + abstr + " ...rest] = fruitything");
eval("var [" + abstr + " ...rest] = fruitything");
answ=prompt("var [" + abstr + " ...rest] = fruitything; /" + "/ using representative Javascript array data here " + String.fromCharCode(10) + String.fromCharCode(10) + ' ... got us to ... ' + String.fromCharCode(10) + String.fromCharCode(10) + 'rest=' + rest, '' + rest);

if (eval('' + iones.length) > 1) {
abstr='';
arestmore='';
xinterim='';
zinterim='';
zone=1;
while (iones[zone] == '') {
xinterim+=' "," + ';
zinterim+=',';
zone++;
}
othera="a";
for (iab=0; iab<iones[zone]; iab++) {
if (arestmore == '') {
arestmore=othera;
//xinterim='';
} else {
arestmore+=' + "," + ' + othera;
//xinterim='';
}
abstr+=othera + ',' + zinterim;
xinterim='';
zinterim='';
if (othera.slice(-1) == 'z') { prefixer=othera; othera+='a'; } else { lastchar=String.fromCharCode(1 + othera.slice(-1).charCodeAt(0)); othera=prefixer + lastchar; }
}
//alert("var [" + abstr.replace(/\,$/g,'') + "] = rest");
eval("var [" + abstr.replace(/\,$/g,'') + "] = rest");
answ=prompt("var [" + abstr.replace(/\,$/g,'') + "] = rest" + String.fromCharCode(10) + String.fromCharCode(10) + ' ... and then ... got us to ... ' + String.fromCharCode(10) + String.fromCharCode(10) + abstr.replace(/\,$/g,'') + '=' + eval(arestmore), '' + eval(arestmore));

}

}
}

… in the changed map_test.html Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Aggregates Tutorial is shown below.

Javascript Map Array Aggregates Tutorial

Javascript Map Array Aggregates Tutorial

The SQL emphasis, recently, regarding our current Arrays and Map web application talked about in yesterday’s Javascript Map Array Delimiter Tutorial had us thinking about if we could incorporate those …

  • count(*)
  • sum(*)
  • min(*)
  • max(*)
  • avg(*)

SQL aggregate function concepts in some way shape or form. Given we’ve gone down the “delimiters logic” road so far, we decided on a pre-emptive approach, where we calculate all the “aggregate” concept values we could think of, ahead of the user even wondering about them, and display them as they are seeing the other data be displayed. Sounds good? We hope so.

Well, see this in action, along with Median and Mode and Standard deviation calculations, as well, in the changed map_test.html Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Delimiter Tutorial is shown below.

Javascript Map Array Delimiter Tutorial

Javascript Map Array Delimiter Tutorial

Regular readers will have tweaked to the “largely delimiter based” logic surrounding the workings of the Array and Map web application of yesterday’s Javascript Map Array SQL Tutorial. To explain our changes, it’s back to a modified blurb

xenterall=prompt(‘Optionally enter a # (hashtag) delimited composite field scenario to apply for next input data (perhaps CSV) file application, such as in examples below where +-*^%/ (maths) and !<>= (conditions) and ~` (for ascending descending order) and | (for OR rather than AND conditions). ‘ + String.fromCharCode(10) + ‘Examples …’ + String.fromCharCode(10) + ‘#1,3&2&4’ + String.fromCharCode(10) + ‘#4,2*3’ + String.fromCharCode(10) + ‘#1&4,3+2’ + String.fromCharCode(10) + ‘#1&4,3&2,2>100|2<-100,`2‘, ”);

… giving a “one role per interesting delimiter” paradigm we’d like to keep, if possible (though behind the scenes we have incorporated backward compatibility).

Can such a delimiter approach handle everything SQL can do? Not a chance, but by the same token, we are not reinventing any wheels with all this, but rather opening up ideas you might want to pick up and run with yourself … or not.

In the changed map_test.html Array and Map Tester web application you can also try below, you may notice other nuances, with logic now supporting …

  1. logic change …
    • OR … WHERE clause parts logic (using that | delimiter mentioned above) … in addition to pre-existing …
    • AND … WHERE clause default logic
  2. changes allowing for yellow cell report toggling between default two column data format and, perhaps, a more extensive report, via a newly introduced ondblclick (on double click) Javascript event function … the changing of which flows through to …
  3. appropriately catering logic to pass this through to email and SMS functionality (and the clicking of links within these)

… nuances pretty critical for many real data set scenarios, we figure.


Previous relevant Javascript Map Array SQL Tutorial is shown below.

Javascript Map Array SQL Tutorial

Javascript Map Array SQL Tutorial

Finishing off the SQL work start that yesterday’s Javascript Map Array Conditions Tutorial represents, today a user can follow the advice

xenterall=prompt(‘Optionally enter a # (hashtag) delimited composite field scenario to apply for next input data (perhaps CSV) file application, such as in examples below where +-*^%/ (maths) and !<>= (conditions) and ~| (for ascending descending order). ‘ + String.fromCharCode(10) + ‘Examples …’ + String.fromCharCode(10) + ‘#1,3&2&4’ + String.fromCharCode(10) + ‘#4,2*3’ + String.fromCharCode(10) + ‘#1&4,3+2’ + String.fromCharCode(10) + ‘#1&4,3&2,2>100,|2‘, ”);

… to facilitate WHERE and ORDER BY processing foreshadowed yesterday.

The ORDER BY solution featured tailored Javascript sort functionality nuances …


function maybesort(rh) {
var recsare=[], newc='', ijk=0, exa='', zero=0, ipo=0;
headrec='';
if (eval('' + orderbys.length) > 0) {
recsare=rh.split(String.fromCharCode(10));
if (recsare[0].indexOf('0') == -1 && recsare[0].indexOf('1') == -1 && recsare[0].indexOf('2') == -1 && recsare[0].indexOf('3') == -1 && recsare[0].indexOf('4') == -1 && recsare[0].indexOf('5') == -1 && recsare[0].indexOf('6') == -1 && recsare[0].indexOf('7') == -1 && recsare[0].indexOf('8') == -1 && recsare[0].indexOf('9') == -1) {
headrec=recsare[0];
zero=1;
efields=headrec.replace(/\"/g,'').split(',');
for (var ke=0; ke<efields.length; ke++) {
eval('mappings.unshift({ from: "' + eval(ke + 1) + '", to: "' + efields[ke] + '"})');
}
document.getElementById('topic').innerHTML=headrec.replace(/^\"/g,'').substring(0).split('"')[0].split(',')[1].substring(0,1).toUpperCase() + headrec.replace(/^\"/g,'').substring(0).split('"')[0].split(',')[1].substring(1);
document.getElementById('thname').innerHTML=maybenotdefn(headrec.replace(/^\"/g,'').substring(0).split('"')[0].split(',')[1].substring(0,1).toUpperCase() + headrec.replace(/^\"/g,'').substring(0).split('"')[0].split(',')[1].substring(1));
document.getElementById('thquantity').innerHTML=maybenotdefq(headrec.replace(/^\"/g,'').substring(0).split('"')[0].split(',')[0].substring(0,1).toUpperCase() + headrec.replace(/^\"/g,'').substring(0).split('"')[0].split(',')[0].substring(1));
analwheres();
}


for (ipo=0; ipo<orderbys.length; ipo++) {


if (orderbys[ipo].indexOf('~1 ') != -1) {
recsare.sort();

} else if (orderbys[ipo].indexOf('|1 ') != -1) {
recsare.sort(function(x, y) {
if (y < x) {
return -1;
}
if (y > x) {
return 1;
}
return 0;
});

} else if (orderbys[ipo].indexOf('|') != -1) {
icol=eval(-1 + eval('' + orderbys[ipo].split('|')[1].split(' ')[0]));
//alert('icol=' + icol);
exa='' + rh.split(String.fromCharCode(10))[zero].split(',')[icol];
//alert('exa=' + exa);
if (exa != '' && exa.replace(/0/g,'').replace(/2/g,'').replace(/3/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').replace(/\-/g,'').replace(/\./g,'').trim() == '') {
//alert('is a number');
recsare.sort(function(x, y) {
if (x != headrec && y == headrec) { return 1; }
if (x == headrec && y != headrec) { return -1; }
if (x == headrec && y == headrec) { return 0; }
if (eval('' + y.split(',')[icol]) < eval('' + x.split(',')[icol])) {
return -1;
}
if (eval('' + y.split(',')[icol]) > eval('' + x.split(',')[icol])) {
return 1;
}
return 0;
});
} else {
recsare.sort(function(x, y) {
if (y.split(',')[icol] < x.split(',')[icol]) {
return -1;
}
if (y.split(',')[icol] > x.split(',')[icol]) {
return 1;
}
return 0;
});
}

} else if (orderbys[ipo].indexOf('~') != -1) {

icol=eval(-1 + eval('' + orderbys[ipo].split('~')[1].split(' ')[0]));
exa='' + rh.split(String.fromCharCode(10))[zero].split(',')[icol];
if (exa != '' && exa.replace(/0/g,'').replace(/2/g,'').replace(/3/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').replace(/\-/g,'').replace(/\./g,'').trim() == '') {
recsare.sort(function(x, y) {
if (x != headrec && y == headrec) { return -1; }
if (x == headrec && y != headrec) { return 1; }
if (x == headrec && y == headrec) { return 0; }
if (eval('' + x.split(',')[icol]) < eval('' + y.split(',')[icol])) {
return -1;
}
if (eval('' + x.split(',')[icol]) > eval('' + y.split(',')[icol])) {
return 1;
}
return 0;
});
} else {
recsare.sort(function(x, y) {
if (x.split(',')[icol] < y.split(',')[icol]) {
return -1;
}
if (x.split(',')[icol] > y.split(',')[icol]) {
return 1;
}
return 0;
});
}

}


newc='';
if (headrec != '') {
newc+=headrec + String.fromCharCode(10);
}
for (ijk=0; ijk<recsare.length; ijk++) {
if (recsare[ijk] != headrec) {
newc+=recsare[ijk] + String.fromCharCode(10);
}
}
//alert(newc);
rh=newc;
}
}
//alert(rh);
return rh;
}

… in the changed map_test.html Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Conditions Tutorial is shown below.

Javascript Map Array Conditions Tutorial

Javascript Map Array Conditions Tutorial

Onto yesterday’s Javascript Map Array Field Tutorial we wanted to extend functionality by starting on a “more than one day” project of thinking …

  • SQL … with it’s … SELECT … statements involving …
  • FROM … clause … representing the input (perhaps) CSV data source … filtered via …
  • WHERE … clauses, for sure … and pretty sure we can manage …
  • ORDER BY … record sorting

… people familiar with working with relative databases will understand.

So far we’re just doing the work to construct the scenario’s SQL “pseudo SELECT statement”. In doing this, we used a new mapping array that could end up looking like …

{from: ‘2’, to: ‘(Longitude+Latitude) as field2’}
{from: ‘4’, to: ‘name’}
{from: ‘3’, to: ‘longitude’}
{from: ‘2’, to: ‘latitude’}
{from: ‘1’, to: ‘country’}
{from: ‘1’, to: ‘Name’}
{from: ‘2’, to: ‘Quantity’}

… where we found building it up via the usual mapping.push() we would use to append data was some of the story, but it’s opposite number mapping.unshift() was really useful to prioritize a changing better to member data item into the mix, as the program flow progesses in the changed map_test.html Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Field Tutorial is shown below.

Javascript Map Array Field Tutorial

Javascript Map Array Field Tutorial

The way the inhouse Javascript Map Array web application worked as of the day before yesterday’s Javascript Map Array Hashtag Tutorial involved …

  • a whole of file (or your entered string) processing of CSV data where the first two fields (comma separated) of records became the name,quantity data basis … but as all Spreadsheet afficianados will tell you, it can be very useful “to drill down” into fields (or “columns”, in Spreadsheet parlance) … so …
  • as of today’s work … well, we’ll let our “blurb”, coming off an H1 tag double click event, to try to explain it …

    var compositename='';
    var compositequantity='';
    var enterall='';

    function anal() {
    enterall=prompt('Optionally enter a # (hashtag) delimited composite field scenario to apply for next input data (perhaps CSV) file application, such as in examples below. ' + String.fromCharCode(10) + String.fromCharCode(10) + 'Examples ...' + String.fromCharCode(10) + '#1,3&2&4' + String.fromCharCode(10) + '#4,2*3' + String.fromCharCode(10) + '#1&4,3+2', '');
    if (enterall.split('#')[0].indexOf(',') == -1 && enterall.trim() != '' && enterall.indexOf('~`~') == -1) {
    compositename='';
    compositequantity='';
    if (enterall.indexOf('#') != -1) {
    var compstuff=enterall.split('#')[1];
    enterall=enterall.split('#')[0];
    var csfs=compstuff.split(',');
    compositename=csfs[0];
    if (compositename != '') {
    if (eval(('' + compositename).split('&')[0].split('+')[0].split('/')[0].split('*')[0].split('-')[0].split('%')[0].split('^')[0]) > 1 && eval('' + csfs.length) <= 1) {
    compositequantity='1';
    } else if (eval('' + csfs.length) > 1) {
    compositequantity=csfs[1];
    }
    }
    }
    enterall='';
    }
    enterall='';
    }

… to allow for some simple mathematical operations (ie. + / – * % ^) of the right hand quantity data item, or concatenation (ie. &) on either left or right (delimited by , comma), as possibilities via user defined field (or “column”) numbering system (starting from 1) means.

Applied to our testing with country.csv here, we started getting scenarios where the Google Chart Geo Chart should turn into “markers mode”, and the statistical Google Chart Area/Bar/Column/Line Charts would have multiple Y axis items for the “name” data item X axis relationship.

More flexibility, we figure, in the extensively changed map_test.html Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Hashtag Tutorial is shown below.

Javascript Map Array Hashtag Tutorial

Javascript Map Array Hashtag Tutorial

Regular readers will know of our ever increasing fondness, out of webpage navigational ideas …

  • form method=GET ? and & delimited argument style URL navigation (suitable for both client and server recipient webpages but apt to cause error 414 due to data size restrictions) … or …
  • form method=POST URL navigation (suitable for server recipient webpages only, but able to handle much more data) … or …
  • hybrid arrangement that is essentially form method=GET ? and & delimited argument style URL navigation (suitable for both client and server recipient webpages) with error 414 avoided by most data forming the location.hash (client understood) hashtagged data

… for the last hashtagging arrangement when the data size precludes the first arrangement, and we see benefits regarding “a” “mailto:” and/or “sms:” sharing links becoming involved (rather than relying on any PHP server mail function calling).

Our Google Chart interfacing is no exception here, and yes, once we’ve completed our sweep of Google Chart inhouse functionality interfacers, on top of today’s …

… list we got keen to attend to today, with a most (when needed) strategy …

First “data” label value is method=GET
Rest of “data” value items are hashtagged

… (having the benefit that the intervention point is consistent and reliable) on top of yesterday’s Javascript Map Array Chart Tutorial, in this regard, as helper outerers for our changed map_test.html Array and Map Tester web application you can also try below, we’ll be able to further genericize Sharing and Collaboration Google Chart interfacing functionality when the amounts of data involved exceed server based (error 414) limits.

Along the way, testing on iOS mobile platforms, we were gobsmacked by the possibility of location.hash (ie. # hashtagging) not being recognized, always, at the recipient, and so a failsafe we introduced was to also store hashtagged data in a parent textbox the recipient can reference …

<?php echo ”

if (window.top) {
if (parent.document.getElementById('lhashis')) {
if (decodeURIComponent(('' + parent.document.getElementById('lhashis').value)).indexOf(',') != -1) {
location.hash=parent.document.getElementById('lhashis').value;
}
}
}

“; ?>

… even before “recipient document.body onload” timing, happily, to get around the restrictiveness of this location.hash lack of acceptance, at times.

Which brings us to …

Why is Geo Chart in that list above?

Well, it’s a bit unlikely, but it just so happens our best CSV file to hand, around here, contained ISO-3166 2 character country codes with a representative latitude and longitude (as you can see with, the now publicly shared, country.csv … thanks to Google) and this data is right up the alley of use by the Google Chart Geo Chart (which you might recall we had a different hashtag arrangement going on already …

… believe it or not, never causing any iOS mobile platform issues up to now … go figure!)

To get this “sharing of that CSV” to be any way useful, and illustrative, if you double click the “topic” word and get to the Javascript prompt window that follows, we tweak you to this, but if you enter …

https://www.rjmprogramming.com.au/HTMLCSS/country.csv

… at that prompt window, now, we’ll attempt an Ajax call of whatever URL you enter to try to glean data content to suit our …

label name to numerical quantity relationship

… this web application is hankering for.

And there, the amount of data (in size) is far too big for non-hybrid method=GET scenarios, and we need to turn to our new hybrid ideas to proceed with our quest to take over “Lower Middle Mordor South Lowlands as seen from Mirkwood“.

This may all bore, but believe me if you offer users a piece of functionality, they’ll want to push it to limits, and in that “push” could come most of your work, and concern, with regard to a project you are working on, so we figure it is best to cater for this before it is asked for.

TwoThree sentences ending in for? Okay, Grammarly, we give up!

Each Google Chart interfacer has individual nuances, but PHP code changes like below …

<?php

echo ' if (decodeURIComponent(("" + location.hash).replace(/^undefined/g,"")).trim().indexOf(",") != -1) { ' . "\n";
echo ' var xwert="data=google.visualization.arrayToDataTable([ [' . "'" . $GETlabel . "','" . str_replace(",", "','", str_replace("'", "", $GETvalue)) . "'" . '],"; ' . "\n";
echo " xwert+=\"" . str_replace("~,", "',", str_replace("[~", "['", str_replace(",]", ",0]", str_replace(",,", ",0,", str_replace(",]", ",0]", $GETdata))))) . "\" + ('' + location.hash).replace(/^\#/g,'').replace(/\%20/g,'').replace(/\,\]/g,\",0\").replace(/\[\~/g,\"['\").replace(/\~\,/g,\"',\"); " . "\n";
echo ' xwert+=" ])"; xwert=xwert.replace(",,",","); ' . "\n";
echo ' eval(xwert); ' . "\n";
echo ' } else { ' . "\n";

echo ' data = google.visualization.arrayToDataTable([ ' . "\n";
echo " ['" . $GETlabel . "','" . str_replace(",", "','", str_replace("'", "", $GETvalue)) . "'] \n";
echo str_replace("~,", "',", str_replace("[~", "['", str_replace(",]", ",0]", str_replace(",,", ",0,", str_replace(",]", ",0]", $GETdata)))));
echo " ]);\n";
echo " } \n";

?>

… typify our interventional strategy to make these improvements happen. Good ol’ (much maligned) eval … huh?! And good ol’ Javascript undefined bizzos! And good ol’ hashtagging! Aaaaaaaaaaal drink to all youse guys and gals (if one might be so forward, that is).


Previous relevant Javascript Map Array Chart Tutorial is shown below.

Javascript Map Array Chart Tutorial

Javascript Map Array Chart Tutorial

Does the data behind yesterday’s Javascript Map Array Import Tutorial remind you of anything? Relative database data? Spreadsheets?

That last one has lots of synergy, we reckon. And lots of us know, in spreadsheet software products like Microsoft Excel, once a …

  • spreadsheet is involved
  • charts are often offered as a graphical stand in display (to the tabular looking spreadsheet, that is)

And in this respect, looking back on our interfacing work to Google Charts when you have a label name to numerical quantity relationship two Google Chart types (we know of) are useful …

… and we’d like to offer some optional interfacing to these (to improve functionality, that is) … the Javascript for this leaning on the new …


function datait(oselv) {
var outv=oselv, kk=0, firstdelim='';
//alert(outv);
if (outv != '') {
if (oselv.indexOf('PHP/Pie') != -1) {
document.getElementById('title').value=document.getElementById('topic').innerHTML + ' ' + document.getElementById('spanok').innerHTML + ' versus ' + document.getElementById('spanlow').innerHTML + ' Report';
document.getElementById('popularity').value=document.getElementById('thquantity').innerHTML;
document.getElementById('task').value=document.getElementById('thquantity').innerHTML;
document.getElementById('country').value=document.getElementById('thname').innerHTML;
document.getElementById('desc').value=document.getElementById('thname').innerHTML;
outv=outv.replace('title=Title', 'title=' + encodeURIComponent(document.getElementById('topic').innerHTML + ' ' + document.getElementById('spanok').innerHTML + ' versus ' + document.getElementById('spanlow').innerHTML + ' Report'));
outv=outv.replace('popularity=Popularity', 'popularity=' + encodeURIComponent(document.getElementById('thquantity').innerHTML));
outv=outv.replace('country=Country', 'country=' + encodeURIComponent(document.getElementById('thname').innerHTML));
outv=outv.replace('task=Popularity', 'task=' + encodeURIComponent(document.getElementById('thquantity').innerHTML));
outv=outv.replace('desc=Country', 'desc=' + encodeURIComponent(document.getElementById('thname').innerHTML));


for (kk=0; kk<fruits.length; kk++) {
if (('~,' + fruits[kk].quantity + ']').replace(/\~\,\]/g,'~,0]').indexOf('-') == -1) {
outv+=',[~' + encodeURIComponent(fruits[kk].name) + ('~,' + fruits[kk].quantity + ']').replace(/\~\,\]/g,'~,0]');
}
}
} else if (oselv.indexOf('PHP/Histogram') != -1) {
document.getElementById('title').value=document.getElementById('topic').innerHTML + ' ' + document.getElementById('spanok').innerHTML + ' versus ' + document.getElementById('spanlow').innerHTML + ' Report';
document.getElementById('popularity').value=document.getElementById('thquantity').innerHTML;
document.getElementById('task').value=document.getElementById('thquantity').innerHTML;
document.getElementById('country').value=document.getElementById('thname').innerHTML;
document.getElementById('desc').value=document.getElementById('thname').innerHTML;
outv=outv.replace('title=Title', 'title=' + encodeURIComponent(document.getElementById('topic').innerHTML + ' ' + document.getElementById('spanok').innerHTML + ' versus ' + document.getElementById('spanlow').innerHTML + ' Report'));
outv=outv.replace('popularity=Popularity', 'popularity=' + encodeURIComponent(document.getElementById('thquantity').innerHTML));
outv=outv.replace('country=Country', 'country=' + encodeURIComponent(document.getElementById('thname').innerHTML));
outv=outv.replace('task=Popularity', 'task=' + encodeURIComponent(document.getElementById('thquantity').innerHTML));
outv=outv.replace('desc=Country', 'desc=' + encodeURIComponent(document.getElementById('thname').innerHTML));


for (kk=0; kk<fruits.length; kk++) {
outv+=',[~' + encodeURIComponent(fruits[kk].name) + ('~,' + fruits[kk].quantity + ']').replace(/\~\,\]/g,'~,0]');
}
//alert(outv);
} else if (oselv.indexOf('PHP/Geo') != -1) {
document.getElementById('title').value=document.getElementById('topic').innerHTML + ' ' + document.getElementById('spanok').innerHTML + ' versus ' + document.getElementById('spanlow').innerHTML + ' Report';
document.getElementById('popularity').value=document.getElementById('thquantity').innerHTML;
document.getElementById('task').value=document.getElementById('thquantity').innerHTML;
document.getElementById('country').value=document.getElementById('thname').innerHTML;
document.getElementById('desc').value=document.getElementById('thname').innerHTML;
outv=outv.replace('title=Title', 'title=' + encodeURIComponent(document.getElementById('topic').innerHTML + ' ' + document.getElementById('spanok').innerHTML + ' versus ' + document.getElementById('spanlow').innerHTML + ' Report'));
outv=outv.replace('popularity=Popularity', 'popularity=' + encodeURIComponent(document.getElementById('thquantity').innerHTML));
outv=outv.replace('country=Country', 'country=' + encodeURIComponent(document.getElementById('thname').innerHTML));
outv=outv.replace('task=Popularity', 'task=' + encodeURIComponent(document.getElementById('thquantity').innerHTML));
outv=outv.replace('desc=Country', 'desc=' + encodeURIComponent(document.getElementById('thname').innerHTML));


for (kk=0; kk<fruits.length; kk++) {
outv+=firstdelim + '%20[~' + encodeURIComponent(fruits[kk].name) + ('~,' + fruits[kk].quantity + ']').replace(/\~\,\]/g,'~,0]') + '%20';
firstdelim=',';
}
if (('' + outv).length > 600) { return toolong(outv.replace('&data=%20', '&data=%20#')); }
}
}
if (('' + outv).length > 600) {
document.getElementById('data').value=',' + outv.split('&data=')[1].replace(/\%20/g,' ');
document.getElementById('myform').method='POST';
document.getElementById('myform').action=outv.split('?')[0] + '#pleasenolocationhref';
outv='./map_test.html';
//var xx=prompt(document.getElementById('myform').outerHTML,document.getElementById('myform').innerHTML);
setTimeout(function(){ document.getElementById('mysub').click(); }, 3000);
} else if (2 == 2) {
document.getElementById('data').value=outv.split('&data=')[1].replace(/\%20/g,' ');
document.getElementById('myform').method='GET';
document.getElementById('myform').action=outv.split('?')[0];
//outv='./map_test.html';
setTimeout(function(){ document.getElementById('mysub').click(); }, 3000);
}
return outv;
}

function selit(osel) {
if (osel.value != '') {
geovalis=osel.value;
document.getElementById('defopt').innerText='Google Chart display of ... relevant ' + osel.value.split('PHP/')[1].split('/')[0].replace('Chart',' Chart') + ' below ...';
document.getElementById('dif').innerHTML='<br><br><a id=atop href="#myh1">Back to top ...</a><br><br><iframe name=myifis id=myifis src="' + datait(osel.value) + '" style="width:100%;height:700px;"></iframe>';
document.getElementById('dif').style.display='block';
}
osel.value='';
location.href='#atop';
}

… in the changed map_test.html Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Import Tutorial is shown below.

Javascript Map Array Import Tutorial

Javascript Map Array Import Tutorial

Is it …

  • the extension of import capabilities … or …
  • the sharing capabilities

… of most interest in today’s work, extending that of yesterday’s Javascript Map Array Genericization Tutorial?

Well …

  • the extension of import capabilities …

    function askall(preenterall) {
    var isfirst=true;
    var delall=false;
    var enterall=('' + preenterall).replace(/^undefined$/g,'');
    if (enterall == '') {
    enterall=prompt('Optionally copy all your CSV (comma separated values) data to apply here (where ; or | can be record delimiters). Optionally prefix this CSV data with your topic followed by ~`~' + String.fromCharCode(10) + String.fromCharCode(10) + 'Example ...' + String.fromCharCode(10) + 'Fish~`~taylor,300;barramundi,400;perch,100;mullet,234', '');
    } //else {
    //alert(enterall);
    //}
    if (enterall == null) { enterall=''; }
    if (enterall.indexOf('~`~') != -1) { document.getElementById('topic').innerHTML=enterall.split('~`~')[0]; enterall=enterall.replace(enterall.split('~`~')[0] + '~`~', ''); }
    if (enterall.indexOf(',') != -1) {
    var elines=[];
    if (enterall.indexOf(String.fromCharCode(10)) != -1) {
    elines=enterall.split(String.fromCharCode(10));
    } else if (enterall.indexOf(';') != -1) {
    elines=enterall.split(';');
    } else if (enterall.indexOf('|') != -1) {
    elines=enterall.split('|');
    }
    for (var ie=0; ie<elines.length; ie++) {
    if (elines[ie].indexOf('","') != -1 && elines[ie].indexOf('","') < elines[ie].indexOf(',')) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(1).replace('-','').substring(0,1) >= '0' && elines[ie].substring(1).replace('-','').substring(0,1) <= '9') {
    //alert(1);
    addone(elines[ie].split('","')[1].split('"')[0], elines[ie].substring(1).split('"')[0]);
    } else {
    //alert(2);
    addone(elines[ie].substring(1).split('"')[0], elines[ie].split('","')[1].split('"')[0]);
    }
    } else if (elines[ie].indexOf('",') != -1 && elines[ie].indexOf('",') < elines[ie].indexOf(',')) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(1).replace('-','').substring(0,1) >= '0' && elines[ie].substring(1).replace('-','').substring(0,1) <= '9') {
    //alert(3);
    addone(elines[ie].split('",')[1].split(',')[0], elines[ie].substring(1).split('"')[0]);
    } else {
    //alert(4);
    addone(elines[ie].substring(1).split('"')[0], elines[ie].split('",')[1].split(',')[0]);
    }
    } else if (elines[ie].indexOf(',"') != -1 && elines[ie].indexOf(',"') == elines[ie].indexOf(',')) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(0).replace('-','').substring(0,1) >= '0' && elines[ie].substring(0).replace('-','').substring(0,1) <= '9') {
    //alert(5);
    addone(elines[ie].split(',"')[1].split('"')[0], elines[ie].substring(0).split(',')[0]);
    } else {
    //alert(6);
    addone(elines[ie].substring(0).split(',')[0], elines[ie].split(',"')[1].split('"')[0]);
    }
    } else if (elines[ie].indexOf(',') != -1) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(0).replace('-','').substring(0,1) >= '0' && elines[ie].substring(0).replace('-','').substring(0,1) <= '9') {
    //alert(7);
    addone(elines[ie].substring(0).split(',')[1], elines[ie].substring(0).split(',')[0]);
    } else {
    //alert(8);
    if (isfirst && ((elines[ie].substring(0).split(',')[1] + ' ').replace('-','').substring(0,1) < '0' || (elines[ie].substring(0).split(',')[1] + ' ').replace('-','').substring(0,1) > '9')) {
    document.getElementById('topic').innerHTML=elines[ie].substring(0).split(',')[0].substring(0,1).toUpperCase() + elines[ie].substring(0).split(',')[0].substring(1);
    document.getElementById('thname').innerHTML=elines[ie].substring(0).split(',')[0].substring(0,1).toUpperCase() + elines[ie].substring(0).split(',')[0].substring(1);
    document.getElementById('thquantity').innerHTML=elines[ie].substring(0).split(',')[1].substring(0,1).toUpperCase() + elines[ie].substring(0).split(',')[1].substring(1);
    } else {
    addone(elines[ie].substring(0).split(',')[0], elines[ie].substring(0).split(',')[1]);
    }
    }
    }
    isfirst=false;
    }
    beadjustable();
    }
    }

    function yesthreethree(restis) {
    if (restis.indexOf(';base64,') != -1) {
    var icontent=window.atob(restis.split(';base64,')[1]);
    if ((('' + icontent).trim() + ' ').replace(/^\[caption/g,'<').substring(0,1) == '<') {
    askall(extractContent(icontent,true));
    } else {
    askall(icontent);
    }
    } else {
    askall(restis);
    }
    }

    …asked for tweaks to our changed client_browsing.htm client side HTML and Javascript inhouse file browsing interfacer showing a “first time” scenario, for us with our “first cab off the rank” CSV (comma separated values) trial file …

    user@MacBook-Air htdocs % head -10 country.csv
    country,latitude,longitude,name // Thanks to https://developers.google.com/public-data/docs/canonical/countries_csv
    AD,42.546245,1.601554,Andorra
    AE,23.424076,53.847818,United Arab Emirates
    AF,33.93911,67.709953,Afghanistan
    AG,17.060816,-61.796428,Antigua and Barbuda
    AI,18.220554,-63.068615,Anguilla
    AL,41.153332,20.168331,Albania
    AM,40.069099,45.038189,Armenia
    AN,12.226079,-69.060087,Netherlands Antilles
    AO,-11.202692,17.873887,Angola
    user@MacBook-Air htdocs %

    … which is of interest … or …
  • the sharing capabilities, of the report, where we allow for the usual onclick of an emoji button fed through to “a” mailto: (email) or sms: (SMS) conduits to sharing, and for the first time, for us, a drag and drop way (we thank both https://www.w3schools.com/howto/howto_js_draggable.asp and https://www.w3schools.com/html/html5_draganddrop.asp regarding) …

    function dragElement(elmnt) { // thanks to https://www.w3schools.com/howto/howto_js_draggable.asp
    var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    if (document.getElementById(elmnt.id + "header")) {
    // if present, the header is where you move the DIV from:
    document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
    } else {
    // otherwise, move the DIV from anywhere inside the DIV:
    elmnt.onmousedown = dragMouseDown;
    }

    function dragMouseDown(e) {
    e = e || window.event;
    e.preventDefault();
    // get the mouse cursor position at startup:
    pos3 = e.clientX;
    pos4 = e.clientY;
    document.onmouseup = closeDragElement;
    // call a function whenever the cursor moves:
    document.onmousemove = elementDrag;
    }

    function elementDrag(e) {
    e = e || window.event;
    e.preventDefault();
    // calculate the new cursor position:
    pos1 = pos3 - e.clientX;
    pos2 = pos4 - e.clientY;
    pos3 = e.clientX;
    pos4 = e.clientY;
    // set the element's new position:
    elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
    elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
    alert('Here');
    }

    function closeDragElement() {
    // stop moving when mouse button is released:
    document.onmouseup = null;
    document.onmousemove = null;
    }
    }

    function allowDrop(ev) { // thanks to https://www.w3schools.com/html/html5_draganddrop.asp
    ev.preventDefault();
    }

    function drag(ev) { // thanks to https://www.w3schools.com/html/html5_draganddrop.asp
    ev.dataTransfer.setData("text", ev.target.id);
    }

    function doemail(data) {
    var a=null;
    a = document.createElement("a");
    var contis=(document.getElementById('demo').innerText || document.getElementById('demo').contentWindow || document.getElementById('demo').contentDocument);
    var topicis=(document.getElementById('topic').innerText || document.getElementById('topic').contentWindow || document.getElementById('topic').contentDocument);
    var subjis=(document.getElementById('threport').innerText || document.getElementById('threport').contentWindow || document.getElementById('threport').contentDocument);
    a.href='mailto:?subject=' + encodeURIComponent(topicis) + '%20' + encodeURIComponent(subjis) + '&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?tippingvalue=' + moreencodeURIComponent(document.getElementById('itip').value) + '#data=') + encodeURIComponent(encodeURIComponent(contis.replace(/\<bJUNKr\>/g, String.fromCharCode(10))));
    a.click();
    }

    function dosms(data) {
    var a=null;
    a = document.createElement("a");
    var contis=(document.getElementById('demo').innerText || document.getElementById('demo').contentWindow || document.getElementById('demo').contentDocument);
    var topicis=(document.getElementById('topic').innerText || document.getElementById('topic').contentWindow || document.getElementById('topic').contentDocument);
    a.href='sms:&body=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0] + '?tippingvalue=' + moreencodeURIComponent(document.getElementById('itip').value) + '#data=') + encodeURIComponent(encodeURIComponent(contis.replace(/\<bJUNKr\>/g, String.fromCharCode(10))));
    a.click();
    }

    function drop(ev) { // thanks to https://www.w3schools.com/html/html5_draganddrop.asp
    var ssrect=null, isemail=true, a=null;
    ssrect=document.getElementById('droppable').getBoundingClientRect();
    if (eval(ssrect.right - ev.clientX) < eval(ev.clientX - ssrect.left)) { isemail=false; }
    ev.preventDefault();
    var data = ev.dataTransfer.getData("text");
    if (isemail) {
    //a = document.createElement("a");
    //a.href='mailto:?subject=' + encodeURIComponent(document.getElementById('topic').innerHTML) + '%20Report%20of%20Inventory&body=' + encodeURIComponent(document.getElementById(data).innerHTML.replace(/\<bJUNKr\>/g, String.fromCharCode(10)));
    //a.click();
    doemail(data);
    } else if (!isemail) {
    //a = document.createElement("a");
    //a.href='sms:&body=' + encodeURIComponent(document.getElementById(data).innerHTML.replace(/\<bJUNKr\>/g, String.fromCharCode(10)));
    //a.click();
    dosms(data);
    } else {
    ev.target.appendChild(document.getElementById(data));
    }
    }

    … where the drop position tells us which “conduit” to go with

… and so, both are of some interest, we figure in a changed map_test.html Array and Map Tester web application you can also try below.

Did you know?

In Object Oriented Programming, methods (ie. object functions) can be named similarly with different argument patterns and/or return values, but now, with three functions in this current project we’ve coalesced this idea into single calls and used the Javascript undefined return for non-defined arguments as our way to “keep it brief” …

  • function askall(preenterall) { } … as above
  • function alteredstate(indemo, readd) { }
  • function addone(knownname, knownquantity) { }


Previous relevant Javascript Map Array Genericization Tutorial is shown below.

Javascript Map Array Genericization Tutorial

Javascript Map Array Genericization Tutorial

We think yesterday’s Javascript Map Array Primer Tutorial could benefit from …

  • aspects that make the Inventory aspects to the web application feel more like a “tool” …
  • aspects that make the Inventory aspects to the web application feel more “generic”

… and, you may notice, fixes for the way “Map.groupBy” functionality does not appear to work on the mobile platforms my iPhone has for web browsers …


var text="";

function thecall() {
var kk=0;

// Group by ok and low
text="These " + document.getElementById('topic').innerHTML.toLowerCase() + "s are Ok: <br>";
try {
const result = Map.groupBy(fruits, myCallback);

// Display Results
try {
for (let x of result.get("ok")) {
if (x.name != '' || x.quantity != 0) {
text += "" + x.name + " " + x.quantity + "<br>";
}
if (!m.has(x.name)) {
m.set(x.name, x.quantity);
}
}
} catch(ebad) { }
text += "<br>These " + document.getElementById('topic').innerHTML.toLowerCase() + "s are low: <br>";
try {
for (let x of result.get("low")) {
if (x.name != '' || x.quantity != 0) {
text += "" + x.name + " " + x.quantity + "<br>";
}
if (!m.has(x.name)) {
m.set(x.name, x.quantity);
}
}
console.log(result.get("ok"));
} catch(ebad) { }
} catch(overebad) {
text="These " + document.getElementById('topic').innerHTML.toLowerCase() + "s are Ok: <br>";
for (kk=0; kk<fruits.length; kk++) {
if (('' + fruits[kk].quantity).replace('-','').substring(0,1) >= '0' && ('' + fruits[kk].quantity).replace('-','').substring(0,1) <= '9') {
if (mysimpleCallback(fruits[kk].quantity) == 'ok') {
//alert(fruits[kk].name);
text += "" + fruits[kk].name + " " + fruits[kk].quantity + "<br>";
//alert('2:' + fruits[kk].name);
if (!m.has(fruits[kk].name)) {
//alert('3:' + fruits[kk].name);
m.set(fruits[kk].name, fruits[kk].quantity);
//alert('4:' + fruits[kk].name);
}
}
}
}
text += "<br>These " + document.getElementById('topic').innerHTML.toLowerCase() + "s are low: <br>";
for (kk=0; kk<fruits.length; kk++) {
if (('' + fruits[kk].quantity).replace('-','').substring(0,1) >= '0' && ('' + fruits[kk].quantity).replace('-','').substring(0,1) <= '9') {
if (mysimpleCallback(fruits[kk].quantity) == 'low') {
text += "" + fruits[kk].name + " " + fruits[kk].quantity + "<br>";
if (!m.has(fruits[kk].name)) {
m.set(fruits[kk].name, fruits[kk].quantity);
}
}
}
}

}

document.getElementById("demo").innerHTML = text;

}

With this in mind, we honed in on a “topic” concept, where yesterday’s “topic” would have been “Fruit”. There are two aspects …

  1. allow a contenteditable way for user to change the displayed (what used to be) hardcoding

    <span title='Double click to be able to enter CSV data' id=topic contenteditable=true onblur=beadjustable(); ondblclick=askall();>Fruit</span>

    … as well as …
  2. add ondblclick (ie. on double click) means by which a user can use a Javascript prompt window means by which they can enter all the CSV (ie. comma separated values) data for an Inventory application of the user’s choosing (including a means by which they can also enter the “topic” at the same time) …

    function askall() {
    var delall=false;
    var enterall=prompt('Optionally copy all your CSV (comma separated values) data to apply here (where ; or | can be record delimiters). Optionally prefix this CSV data with your topic followed by ~`~' + String.fromCharCode(10) + String.fromCharCode(10) + 'Example ...' + String.fromCharCode(10) + 'Fish~`~taylor,300;barramundi,400;perch,100;mullet,234', '');
    if (enterall == null) { enterall=''; }
    if (enterall.indexOf('~`~') != -1) { document.getElementById('topic').innerHTML=enterall.split('~`~')[0]; enterall=enterall.replace(enterall.split('~`~')[0] + '~`~', ''); }
    if (enterall.indexOf(',') != -1) {
    var elines=[];
    if (enterall.indexOf(String.fromCharCode(10)) != -1) {
    elines=enterall.split(String.fromCharCode(10));
    } else if (enterall.indexOf(';') != -1) {
    elines=enterall.split(';');
    } else if (enterall.indexOf('|') != -1) {
    elines=enterall.split('|');
    }
    for (var ie=0; ie<elines.length; ie++) {
    if (elines[ie].indexOf('","') != -1 && elines[ie].indexOf('","') < elines[ie].indexOf(',')) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(1).replace('-','').substring(0,1) >= '0' && elines[ie].substring(1).replace('-','').substring(0,1) <= '9') {
    addone(elines[ie].split('","')[1].split('"')[0], elines[ie].substring(1).split('"')[0]);
    } else {
    addone(elines[ie].substring(1).split('"')[0], elines[ie].split('","')[1].split('"')[0]);
    }
    } else if (elines[ie].indexOf('",') != -1 && elines[ie].indexOf('",') < elines[ie].indexOf(',')) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(1).replace('-','').substring(0,1) >= '0' && elines[ie].substring(1).replace('-','').substring(0,1) <= '9') {
    addone(elines[ie].split('",')[1].split(',')[0], elines[ie].substring(1).split('"')[0]);
    } else {
    addone(elines[ie].substring(1).split('"')[0], elines[ie].split('",')[1].split(',')[0]);
    }
    } else if (elines[ie].indexOf(',"') != -1 && elines[ie].indexOf(',"') == elines[ie].indexOf(',')) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(0).replace('-','').substring(0,1) >= '0' && elines[ie].substring(0).replace('-','').substring(0,1) <= '9') {
    addone(elines[ie].split(',"')[1].split('"')[0], elines[ie].substring(0).split(',')[0]);
    } else {
    addone(elines[ie].substring(0).split(',')[0], elines[ie].split(',"')[1].split('"')[0]);
    }
    } else if (elines[ie].indexOf(',') != -1) {
    if (!delall) {
    delall=true;
    fruits=[];
    m = new Map();
    }
    if (elines[ie].substring(0).replace('-','').substring(0,1) >= '0' && elines[ie].substring(0).replace('-','').substring(0,1) <= '9') {
    addone(elines[ie].substring(0).split(',')[1], elines[ie].substring(0).split(',')[0]);
    } else {
    addone(elines[ie].substring(0).split(',')[0], elines[ie].substring(0).split(',')[1]);
    }
    }
    }
    beadjustable();
    }
    }

… in a changed map_test.html “proof of concept” Array and Map Tester web application you can also try below.


Previous relevant Javascript Map Array Primer Tutorial is shown below.

Javascript Map Array Primer Tutorial

Javascript Map Array Primer Tutorial

We’ve got yet another “map” idea for you today, coming from the wooooorrrrlllllddd of Javascript clientside data structures, if you like.

We got onto this topic via reading https://www.w3schools.com/js/tryit.asp?filename=tryjs_map_groupby and https://medium.com/@sotoer/your-foreach-example-has-the-wrong-order-of-params-which-you-are-also-demonstrating-in-your-sample-42f5491b604e which both helped us enormously put together a rudimentary Fruit Inventory web application featuring …

  • array with structure

    // Create an Array
    const fruits = [
    {name:"apples", quantity:300},
    {name:"bananas", quantity:500},
    {name:"oranges", quantity:200},
    {name:"kiwi", quantity:150}
    ];
  • map object

    var m = new Map();
  • use of map.set() …

    function addone() {
    doadd=true;
    fruits.push({name:"", quantity:0});
    m.set('', 0);
    doadd=false;
    beadjustable();
    }

    … and Map.groupBy()

    function thecall() {
    // Group by ok and low
    const result = Map.groupBy(fruits, myCallback);

    // Display Results
    let text ="These fruits are Ok: <br>";
    try {
    for (let x of result.get("ok")) {
    if (x.name != '' || x.quantity != 0) {
    text += x.name + " " + x.quantity + "<br>";
    }
    if (!m.has(x.name)) {
    m.set(x.name, x.quantity);
    }
    }
    } catch(ebad) { }
    text += "<br>These fruits are low: <br>";
    try {
    for (let x of result.get("low")) {
    if (x.name != '' || x.quantity != 0) {
    text += x.name + " " + x.quantity + "<br>";
    }
    if (!m.has(x.name)) {
    m.set(x.name, x.quantity);
    }
    }
    } catch(ebad) { }
    document.getElementById("demo").innerHTML = text;

    console.log(result.get("ok"));
    }
  • contenteditable=true

    function consolelog(inrec) {
    if (rspan == 0) {
    document.getElementById("tdname").innerHTML=inrec.split('value:')[1].split(' key:')[0].split(' map:')[0];
    document.getElementById("tdquantity").innerHTML=inrec.split('key:')[1].split(' value:')[0].split(' map:')[0];
    rspan=1;
    } else if (inrec.split('value:')[1].split(' key:')[0].split(' map:')[0] == '') {
    tabletds+='<tr><td contenteditable=true id=tdname' + rspan + ' onblur=fix(this);>' + inrec.split('value:')[1].split(' key:')[0].split(' map:')[0] + '</td><td contenteditable=true id=tdquantity' + rspan + ' onblur=fix(this);>' + inrec.split('key:')[1].split(' value:')[0].split(' map:')[0] + '</td></tr>';
    rspan++;
    } else {
    tabletds+='<tr><td contenteditable=false id=tdname' + rspan + ' onblur=fix(this);>' + inrec.split('value:')[1].split(' key:')[0].split(' map:')[0] + '</td><td contenteditable=true id=tdquantity' + rspan + ' onblur=fix(this);>' + inrec.split('key:')[1].split(' value:')[0].split(' map:')[0] + '</td></tr>';
    rspan++;
    }
    //alert(inrec);
    if (doadd) {
    fruits.push({name:"", quantity:0});
    m.set('', 0);
    tabletds+='<tr><td contenteditable=true id=tdname' + rspan + ' onblur=fix(this);></td><td contenteditable=true id=tdquantity' + rspan + ' onblur=fix(this);>0</td></tr>';
    rspan++;
    doadd=false;
    }
    }
  • array.push()

… in map_test.html “proof of concept” Array and Map Tester web application …

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.


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.


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

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