Javascript Map Array Genericization Tutorial

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.

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

Javascript Map Array Primer Tutorial

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.

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

PHP Mbstring Multibyte String and Intl Class Tutorial

PHP Mbstring Multibyte String and Intl Class Tutorial

PHP Mbstring Multibyte String and Intl Class Tutorial

We’re revisiting the PHP Mbstring Multibyte String Primer Tutorial of the past to see where we stand now with PHP 8 and …

  • mbstring “Multibyte String” extension … and …
  • intl “Internationalization Functions” extension

… and discovered that we can happily now have a chance incorporating these functionalities into PHP serverside logic into the future. We tested this with a tweaked mbstring_test.php “old way” live run and “new way” live run via the writing of a couple of “proof of concepts” …


Previous relevant PHP Mbstring Multibyte String Primer Tutorial is shown below.

PHP Mbstring Multibyte String Primer Tutorial

PHP Mbstring Multibyte String Primer Tutorial

Our (Mac OS X laptop) local MAMP web server is an Apache/PHP/MySql web server. In this environment you can find out a lot with some PHP code as per …

<?php phpinfo(); ?>

… and if, in doing this, you find a reference to the “mbstring” Multibyte String Information functionality existing, you are a lucky candidate to introduce some internationalization code into your PHP code, for those occasions where the destination language uses a UTF-8 character set where individual characters can not be described by the ascii character set from decimal 0 to decimal 255. In other words, it takes more than one byte to describe each character of the language. There are many languages like this, a few being the Chinese languages, Japanese and Korean.

We followed a lot of the advice of the very useful link (thanks) to create some PHP called …

… where we show what we always suspected but were too shy to ask, and didn’t flesh it out before … doh! … you can’t split a Chinese phrase’s characters into their individual characters and expect those characters individually translated bring you back to the sense of the Chinese phrase to start with.

So we take the Chinese phrase 火车票 (which translates into English as “Train tickets” … and we thank Google Translate for help with all this) and use PHP mbstring’s mb_str_split to properly split the Chinese into its constituent multibyte (UTF-8) characters (and along the way, show that PHP str_split messes up this same task, as you’d probably guess would happen), and then translate all these into English using Google Translate, as an intellectual exercise.

If this exercise makes you …

  • a) fall on the floor laughing
  • b) hit a gong with a huge hammer
  • c) cook up some deep fried dumplings
  • d) put the left chopstick in the right ear and the right chopstick in the left ear (please ask for adult supervision) … translation: do not do this
  • e) while reading you sweep the cat under the rug (no animals were harmed in the making of this blog posting)

… then we’re here to tell you that you need to take a Bex and have a lie down.

We are just showing in PHP that if the mbstring functionality is available to you, that the mbstring library of functionality can help with some Internationalization issues you may be grappling with and that this PHP code you could try via this live run link.

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

Imagick PHP Class Primer Tutorial

Form Target Self Primer Tutorial

Imagick PHP Class Primer Tutorial

We’re talking “class” today. Up until now, regarding the great ImageMagick suite of software, and it’s interactions with PHP, we’ve …

… in a first draft not installed here on CentOS but okay here with AlmaLinux. Am sure most people would concur that this is much more integrated approach for PHP …


<?php
// oil_painting_thumbnail.php
// RJM Programming - August, 2024
// Start using PHP Imagick class
$image=null;
if (!isset($_GET['image']) && !isset($_POST['image'])) {
echo "<html><head><scr" . "ipt type=text/javascript> function ask() { var bsh=prompt('See the default brightness, saturation, hue settings, black point %, white point % and change as desired ... 100,0,100,90,95 is grayscale ... darkest 90% of pixels are turned black, the brightest 5% are made white, and those between 90% and 95% are grey-scaled', document.getElementById('brightness').value + ',' + document.getElementById('saturation').value + ',' + document.getElementById('hue').value + ',' + document.getElementById('blackpoint').value + ',' + document.getElementById('whitepoint').value); if (bsh != null) { if (eval('' + bsh.split(',').length) == 5) { document.getElementById('brightness').value=bsh.split(',')[0]; document.getElementById('saturation').value=bsh.split(',')[1]; document.getElementById('hue').value=bsh.split(',')[2]; document.getElementById('blackpoint').value=bsh.split(',')[3]; document.getElementById('whitepoint').value=bsh.split(',')[4]; } } return true; } </scr" . "ipt></head><body><h1>Imagick Ideas</h1><h3>RJM Programming - August, 2024 ... thanks to https://www.php.net/manual/en/book.imagick.php and https://www.php.net/manual/en/imagick.contraststretchimage.php</h3><br><br><form action='./oil_painting_thumbnail.php' id=myform method=GET><input type=hidden name=brightness value=100 id=brightness></input><input type=hidden name=saturation value=0 id=saturation></input><input type=hidden name=hue value=100 id=hue></input><input type=hidden name=blackpoint value=90 id=blackpoint></input><input type=hidden name=whitepoint value=95 id=whitepoint></input><input style='width:70%;' type=text placeholder='Image to process ...' name=image id=image value=''></input><br><br><input onclick=\" document.getElementById('myform').method='GET'; \" type=submit style=background-color:orange; value=Negate></input> <input style=background-color:yellow; onclick=\" if (ask()) { document.getElementById('myform').method='POST'; } \" type=submit value='Contrast Stretch'></input></form></body></html>";
} else {
if (isset($_GET['image'])) {

header('Content-type: image/jpeg');

//Instantiate a new Imagick object
$image = new Imagick(realpath(urldecode($_GET['image'])));
$image->negateImage(false);

// If 0 is provided as a width or height parameter,
// aspect ratio is maintained
$image->thumbnailImage(100, 0);

echo $image;
exit;

} else {
//Instantiate a new Imagick object
$image = new Imagick(realpath(urldecode($_POST['image'])));
list($width, $height) = array_values ($image->getImageGeometry());
$b=(isset($_POST['brightness']) ? $_POST['brightness'] : '100');
$s=(isset($_POST['saturation']) ? $_POST['saturation'] : '0');
$h=(isset($_POST['hue']) ? $_POST['hue'] : '100');
$bp=(isset($_POST['blackpoint']) ? $_POST['blackpoint'] : '90');
$wp=(isset($_POST['whitepoint']) ? $_POST['whitepoint'] : '95');
$image->modulateImage($b, $s, $h);
$image->contrastStretchImage($width * $height * ($bp / 100.0), $width * $height * ($wp / 100.0));
$image->writeImage('example_thumbnail.jpg');
echo "<html><body><p>My Changed Image " . urldecode($_POST['image']) . " ... brightness " . $b . ", saturation " . $s . ", hue " . $h . ", black point % " . $bp . "%, white point % " . $wp . "%</p><br><img src='./example_thumbnail.jpg'></img></body></html>";
exit;

}
}
?>

… to interface to the great ImageMagick image manipulation software.

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

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

AlmaLinux Web Server Malware Scanning Tutorial

AlmaLinux Web Server Malware Scanning Tutorial

AlmaLinux Web Server Malware Scanning Tutorial

If you maintain a computer it can be reassuring to have access to some quality Malware Scanning functionality (often part of an AntiVirus suite of functionality located, for us, in amongst the cPanel functionality of our AlmaLinux WHM Linux web server software parts). So it is with our “soon to be” RJM Programming AlmaLinux web server, which has provided us with ImunifyAV

ImunifyAV: Best Free Linux Server Antivirus

… 7.14.0 version, further to previous malware blog posting regarding laptop themed Malware Protection Primer Tutorial.

We’ve used ImunifyAV a few times, now, on our AlmaLinux web server, and find it easy to use, starting a session scanning …


/home*/*

… folder specification, which covers the public parts of the RJM Programming domain reach.

But we have come across some false positive Malware readings …

How do we know? It’s the combination of …

  • what it suspected was inhouse code … and …
  • we stopped it being flagged as “malware” via …
    1. copied the code to a newly created folder (for speed of scanning purposes)
    2. found that for two inhouse code examples, now, by changing codelines that used to look like …

      [some code statement]; // thanks to https://[domain]/[requestURI]

      … to …

      [some code statement]; // thanks to https [domain] [requestURI]

      … and the fact that this took the code off that “malware” suspicion list made us think that “signature based” malware checking can throw up very occasional false positives
  • delete this code and its temporary folder
  • make the changes to the original code
  • rerun the /home*/* (or subset) scanning run, to reassure

So, if a small number of these inhouse examples are found we recommend not panicking, and checking each one out for these “what must be signature based” Malware Scanning accidental “false positives”. Else if still flagged … panic! But seriously, you may need to examine further, or quarantine, via deletion perhaps, or purchase more ImunifyAV functionality that purports to fix such malware issues.


Previous relevant Malware Protection Primer Tutorial is shown below.

Malware Protection Primer Tutorial

Malware Protection Primer Tutorial

To quote Wikipedia, Malware is …

Malware (a portmanteau for malicious software) is any software intentionally designed to cause damage to a computer, server, client, or computer network.[1] Malware does the damage after it is implanted or introduced in some way into a target’s computer and can take the form of executable code, scripts, active content, and other software.[2]

… and as such, should not be confused with another security concern called “computer viruses” … Wikipedia again …

A computer virus is a type of malicious software that, when executed, replicates itself by modifying other computer programs and inserting its own code.[1] When this replication succeeds, the affected areas are then said to be “infected” with a computer virus.[2][3]

Confusion could mean that you think a “computer virus” scanning system will protect you from Malware. If the scanning product doesn’t say so, it doesn’t. On our MacBook Pro we got offered the chance to try out a Malware controlling piece of software called Malwarebytes, and we’ve been using its simple interface to scan for Malware at regular intervals. We like it, and think you may like it too … hence the blog posting, for your perspicacious self, like.

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


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

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

Spotify and Sonos Bluetooth Speaker Tutorial

Spotify and Sonos Bluetooth Speaker Tutorial

Spotify and Sonos Bluetooth Speaker Tutorial

We can only sit back and admire the “hardware and networking and software aspects” to using a …

  1. Spotify music playing subscription iOS app software arrangement (paid for avoids advertisements) … played via Bluetooth through …
  2. Sonos (Era 100) single speaker

… combination of products. Once arranged, given we had the Spotify app and subscription organized already (as we alluded to with Spotify Bluetooth Speaker Volume Tutorial below), and that is pretty simple as far as Sonos goes (it’s Era 100 pamphlette describing it …

1 Connect the power cord
2 Download the Sonos app for setup

and we did not find it much worse than that (even with our FOBP (“Fear of Bluetooth Pairing”) phobia)), any day or hour of listening is just a case of

  • on our iPhone with the Spotify app associated with the subscription and used to set up the Sonos speaker (and we’re not even going into some additional Wi-Fi functionality available too) …
  • Settings -> Bluetooth … tap (hopefully) On >
  • as required, if Room Name (SONOS) “Not Connected” tap to make it “Connected”
  • open Spotify app
  • pick music to play and tap it’s icon …
  • tap the Play button (perhaps only this once, for the day (and as a sometime media interfacing iOS programmer, that is a feat!))

That’s it! But let’s just hope all those great and entertaining musicians are getting rewarded appropriately too.


Previous relevant Spotify Bluetooth Speaker Volume Tutorial is shown below.

Spotify Bluetooth Speaker Volume Tutorial

Spotify Bluetooth Speaker Volume Tutorial

Am wondering whether anybody else out there is like me and cannot commit to “day to day working memory” …

? Do you think I can nail that last step?! I mean, that last step confounds me every time! Maybe this blog posting can help me, and maybe you, to commit to memory, where on Spotify you can get to change the volume on those bluetooth speakers …


There's a bluetooth icon down near the bottom of the screen a little right of centre (with special consideration for people who think Spotify is all smoke and mirrors)

… which gets you to a draggable volume controller. Yayyyyyyyy!


Previous relevant Spotify Queue Album in Order Primer Tutorial is shown below.

Spotify Queue Album in Order Primer Tutorial

Spotify Queue Album in Order Primer Tutorial

Spotify has changed the way a lot of us listen to music online. The huge pull for its audience are the number of arrangements it has with music labels to be able to build a huge music repository publicly available online.

Using Spotify though, the easiest way to arrange the music playing is via a “Shuffle Play” of the songs of the sources you choose, whether that be by individual artist or podcast or album or genre. Some albums though, at least to our mind, are like a story, and they have been developed with a purpose or theme in mind, and as such, can be best played in the song order chosen by the artist or that artist’s agents, for that album. Don’t think there are any buttons as such for this on the Spotify app, today’s video showing the iOS app version on an iPhone. But this is possible, and the purpose of today’s tutorial is to talk about the Spotify “play queue” and in the process how to achieve this.

  1. Clear the existing queue first by …
    • Tap on song currently playing
    • Tap top right icon … shows songs on the queue
    • Check all the boxes on left
    • Tap “Remove” button at bottom left to clear the queue
    • Go back with down arrow top left icon tap
  2. Search for album name via bottom magnifying glass icon tap … type in album name in resultant textbox … go (swipe) down to Album section and tap the album
  3. Swipe to right on each song of that album in order … and a “Queued” message will briefly verify that operation
  4. Optionally choose more music to be queued up by returning to step 2 above
  5. Your choices will be played in that order after any currently playing song

Have a geek at this demonstrated by us, below …

We hope this might be of some use to some Spotify users out there! Happy listening!

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


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


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

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

Google Chart Geo Chart Interfacing Migration to PHP8 Tutorial

Google Chart Geo Chart Interfacing Migration to PHP8 Tutorial

Google Chart Geo Chart Interfacing Migration to PHP8 Tutorial

You may have read in AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial how RJM Programming Apache/PHP/MySql hosting will eventually move from a …

  • PHP version starting with “5” … to …
  • PHP version starting with “8”

If your reaction is …

So what?

… we admire your panache, but if you’re the duck wading through the near shoreline weeds, and the legs aren’t working too well …

Life wasn’t meant to be easy.

We picked the interfacing to the Google Chart Geo Chart inhouse interfacer PHP web application as our opening gambit, figuring it would have extensive issues … and it did not fail to disappoint in this respect …

… 3 hours later …

What can we say? As a precis …

  • $_SERVER[‘HTTP_REFERER’] is deprecated
  • $_GET[‘alabel’] and/or $_POST[‘alabel’] type “globals”, if undefined, should not appear that way (nor other undefined non-global ones), exposed, unless, maybe, with a ternary PHP isset based intervention, you check for existence dynamically so as to avoid this “exposure”

… and yes, we were well into PHP5 looseness … hence the 3 hours to get to some PHP8 sanguinity!

And what was our great friend here? No need for any PHP debuggers, just good ol’ Google Chrome web browser Web Inspector debugging was fine and PHP errors and warnings would be derivable via PHP statements output and available through the Web Inspector tab called “Console”.

And so, feel free to try the changed geo_chart.php the old way to Geo Chart and now, the new way to Geo Chart.


Previous relevant AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial is shown below.

AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial

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 …

  • data migration … which our web hoster, Crazy Domains, did a good job regarding … ahead of …
  • seeing HTML and Javascript and CSS working fine straight away … and today’s progress migrating the WordPress Blog (involving serverside PHP and MySql) you are reading now …

… in terms of a migration consisting of (just in terms of major players) …

Description From To
Hosting VPS CentOS 6.4 x86.64 WHM cPanel 11.38.2 (build 23) AlmaLinux 9.4.0 cPanel 11.120
Operating System type Linux 2.6.32-220.13.1.el6.x86_64 Linux 5.14.0-362.18.1.el9_3.x86_64
Web Server type Apache 2.2.29 Apache 2.4.61
Server Language PHP 5.4.38 PHP 8.1.19
Database type MySql 5.1.70 MySql 8.0.38
Blog type WordPress 4.1.1 WordPress 6.6

… that PHP leap very big (and we were near an edge regarding PHP 5.4.38 where a WP-CLI approach as below can still work … some earlier 5’s will not work, we were told along the way), and trepidatious, to our mind, but at least for WordPress, now working, via (just highlights, and we’ll leave out that it is great to have a backup of the MySql WordPress software and database ideally, before starting (because we already had one courtesy of the data migration above)) …

  1. install WP-CLI … via ssh -p 22 [adminUser]@[newIPaddressForRJMProgrammingIntoTheFuture] … profuse thanks to this great advice

    # cd ~[websiteUser]
    # cd public_html/ITblog
    # curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    # php wp-cli.phar --info
    # chmod +x wp-cli.phar
    # mv wp-cli.phar /usr/local/bin/wp
  2. run the plan ideas past Crazy Domains
  3. just install the WordPress Codex software in wp-admin and wp-includes … via ssh -p 22 [adminUser]@[newIPaddressForRJMProgrammingIntoTheFuture]

    # su - [websiteUser]
    $ cd ~[websiteUser]
    $ cd public_html/ITblog
    $ wp core download --force --skip-content
  4. iron out just the one (yee, ha) plugins and/or theme issues that can occur entering a URL such as https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog into a web browser address bar … removing …

    New Google Plus Badge Widget

    … plugin folder and files, because it’s name was apparent in the error message in the video below, and once done WordPress 6.6 starting looking like it’s old self … yee, ha
  5. amend wp-config.php to add in code statement … thanks to this great advice

    define('RELOCATE',true);

    … meaning URLs such as https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog just address data and software on [newIPaddressForRJMProgrammingIntoTheFuture] proposed new AlmaLinux9 web server (rather than ducking off to https://www.rjmprogramming.com.au/ITblog/ or https://[oldIPaddressForRJMProgrammingFromTheNearFuturePast]/ITblog/)
  6. on our way to WordPress admin section via https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog/wp-admin into the web browser address bar …

    WordPress MySql database was updated (to align with PHP 8.1.19 and MySql 8.0.38 and WordPress 6.6 requirements)
  7. in WordPress admin section General Settings make sure both WordPress Address (URL) and Site Address (URL) get mapped to …

    https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog

    … during our migration phase, at least
  8. practice writing …

    Blog posts

    … in WordPress Code editor (showing HTML, as we are most familiar with, but you can edit in a visual mode of use, if you like)

Feel free to see some of what we did here in video below …


Previous relevant Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial is shown below.

Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial

Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial

One of the most amazing aspects to the Crazy Domains performed data migration for the RJM Programming domain on 17/1/2023, thanks, was the way, from our point of view, it was …

Changed No change
IP address Any usernames
Power management Any passwords
DNS mappings ssh access (just with changed IP address slotted in for old one)
sftp access
cPanel access (just with changed IP address slotted in for old one)

… with so little affecting our day to day interactions with the website.

And so, on this topic, adding to the recent Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial we want to hone in on that Any usernames and Any passwords resisting any need to change. How so? Well, it’s to do with how ssh and sftp and RSA keys and Fingerprints work. Let’s ask experts some questions.

How does ssh use rsa keys to help with login?

And we liked What Is an SSH Key? Generation, Authentication, Key Pair Info & More

How does SSH RSA key work?

An SSH key relies upon the use of two related keys, a public key and a private key, that together create a key pair that is used as the secure access credential. The private key is secret, known only to the user, and should be encrypted and stored safely.

That “stored safely” is the key (chortle, chortle) to the cleverness of the system. The key is stored on the same web server disk migrated, and so access to a username’s previous password is maintained that way.

How does ssh use a fingerprint to help with login?

And we liked Check the SSH host fingerprint of a server with the web console

Secure Shell (SSH) uses a fingerprint generated with the unique server host key so that a client can identify the server. Whenever the host fingerprint changes, SSH issues the following warning: The host fingerprint can’t be verified or it has changed. When you configure the SSH server, the host key generates randomly.

And so, we can see that the fingerprint mechanism can help the user authenticate, and have the key refresh itself, in the new web server IP address environment, as you can see in today’s tutorial picture.

Cute, huh?!


Previous relevant Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial is shown below.

Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial

Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial

Regarding Apache/PHP/MySql web hosting, and the recent Apache/PHP/MySql Web Hosting Website Migration Tutorial‘s subject matter regarding a Crazy Domains inspired Data Migration here at RJM Programming on 17/1/2023, we wanted to go over a last set of DNS setting …

The Domain Name System (DNS) is a hierarchical and distributed naming system for computers, services, and other resources in the Internet or other Internet Protocol (IP) networks. It associates various information with domain names assigned to each of the associated entities. Most prominently, it translates readily memorized domain names to the numerical IP addresses needed for locating and identifying computer services and devices with the underlying network protocols.[1] The Domain Name System has been an essential component of the functionality of the Internet since 1985.

… steps that represented that final “tying the knot” of repositioning the RJM Programming domain to a new IP address and allowing cPanel and ssh and sftp website access methods not have to change regarding username and password usage, just IP addresses, perhaps totally “behind the scenes”. Think of it like a “renaming the underbelly” exercise, perhaps!

Until these DNS settings are adjusted in “A records” up at the web hoster by the Webmaster or Web Hoster, and there is, typically, about a five minute wait afterwards, the website cannot be reached via your usual …


https://www.rjmprogramming.com.au

… web browser address bar way to navigate to the Landing Page of the RJM Programming domain.

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