We came across it again the other day re-reading Colour Wheel Canvas Analogue Clock Background Blend Mode Tutorial. Weโre sure weโve remedied it, in various ways on various occasions.
Whatโs it? Glad you asked.
Information technology (IT) is a set of related fields that encompass computer systems, software, programming languages, and data and information processing, and storage.[1] IT forms part of information and communications technology (ICT).
Sorry, wrong cue card โฆ transmission will resume shortly.
Itโs the scenario where โฆ
- an iframe HTML element is placed down a ways into a webpage hosted by, in our case โฆ
- a WordPress blog webpage โฆ and โฆ
- that iframeโs Javascript or HTML causes a scrolling action to happen within it on or after itโs onload event logic via, off the top of our head, one of โฆ
- [HTMLelement].focus(); // to textarea or input textbox element (on non-mobile โฆ on mobile, this would be ignored)
- [HTMLelement].scrollIntoView();
- window.scrollTo([leftpx], [toppx]);
- location.href=โ#[HTMLid]โ;
- location.hash=โ#[HTMLid]โ; // might be something to worry about
- iframe src attributeโs URL has a #[HTMLid] hashtag repositioning down a ways โฆ might also be something to worry about
โฆ causing a jittery effect for a user in all probability wanting to read the blog posting content from the top rather than being forced to have the iframe โin the foldโ as they open the blog posting, and them having to manually scroll up to get to what they intended to read, first.
In amongst various ways weโve used in the past to remedy, off the top of our head, in the past โฆ
- weโve added into the iframeโs Javascript code like (where the example tries to remedy a [HTMLelement].focus(); type scenario, but could just as easily be applied to other types of scenarios detected on or after the document.body onload event) โฆ
<html><body onload=" if (window.self != window.parent) { document.getElementById('textbox_to_focus').value=document.getElementById('textbox_to_focus').value; } else { document.getElementById('textbox_to_focus').focus(); } ">[ ... webpage content ... ]</body></html>
โฆ with maybe an 80% success rate โฆ but then we remember another circumventory approach as per the previous Image Filter Display Tutorial โฆ - an approach within the remit of the hosterโs Content Management System (ie. a blog postingโs HTML content) that within the iframeโs callโs blog posting content we add a fix like โฆ
<iframe onload="setTimeout(function(){ location.href='#content'; }, 7000);" style='width:100%;height:1500px;' src='//www.rjmprogramming.com.au/PHP/read_exif_off_image_rotate.php?image=./street_art_katoomba.gif'></iframe>
โฆ so that the jitteriness becomes short lived. You want better than short lived? Use some version of the first methodology sets of the two sets above.
What remedy did we apply to Colour Wheel Canvas Analogue Clock Background Blend Mode Tutorial, featuring in todayโs animated GIF presentation, and itโs ilk (ie. other blog postings in a thread will suffer as well)?
<iframe scrolling=no onload="setTimeout(function(){ top.location.href='#content'; }, 5000);" style='width:100%;height:900px;' src='https://www.rjmprogramming.com.au/HTMLCSS/circular_text.html?radius=320.360&text=1%3Cspan%3E2%3C%2Fspan%3E1234567891%3Cspan%3E0%3C%2Fspan%3E1%3Cspan%3E1%3C%2Fspan%3E%3Ciframe%20frameborder%3D0%20style%3D%27z-index%3A23%3Bmargin-left%3A127px%3Bmargin-top%3A130px%3Bheight%3A400px%3B%27%20src%3Danalogue_clock.htm%23xbody%3E%3C%2Fiframe%3E'></iframe>
Previous relevant Image Filter Display Tutorial is shown below.
Weโre glad todayโs โImage Filter Display Tutorialโ blog posting title is shorter than yesterdayโs โAnimated GIF Duration Calculation Filter Browsing Tutorialโ because the main task today was โฆ
- to take all our โproof of conceptโ web applications and distil them down to an โImage Filter Displayโ web application of far greater simplicity โฆ and along that way โฆ
- we had to play around with one more โproof of conceptโ idea, that of allowing the user to control the content of the CSS filters dropdown, and our first โout thereโ thought that contenteditable=true could be applied to all the dropdownโs option elements to achieve this needed to be disproved (as it took two hours to be sure of โฆ to be sure) โฆ in favour of a new dropdown โChangeโ option solution โฆ
function callresell() {
var oselo=document.getElementById('simgag');
var svalis='';
var sc=';';
var changefound=false;
if (document.getElementById('imgag')) {
oselo.value=document.getElementById('imgag').title;
}
var reselit=prompt('Please change the semicolon separated options list. Optionally hash # separate a CSS filter refresh interval in seconds (currently ' + eval(Math.abs(ingifint) / 1000.000) + ' seconds).', oselo.innerText);
if (reselit != null) {
if (reselit.indexOf('#') != -1) {
if (ingifint < 0) {
ingifint=Math.round(eval(-1000.0 * eval('' + reselit.split('#')[1].split(';')[0])));
} else {
ingifint=Math.round(eval(1000.0 * eval('' + reselit.split('#')[1].split(';')[0])));
}
reselit=reselit.replace('#' + reselit.split('#')[1].split(';')[0], '');
}
}
if (reselit == null) {
return '';
} else if (reselit != oselo.innerText) {
var sih=oselo.innerHTML;
var vsl=reselit.split(';');
var shi=sih.split('</option>');
var ssize='' + oselo.size;
var vssize=0;
var newih='';
for (var ihi=0; ihi<vsl.length; ihi++) {
if (vsl[ihi].trim() != '') {
if (vsl[ihi].trim() == 'Change') { changefound=true; sc=''; } else { sc=';'; }
if (eval('' + shi.length) > ihi) {
if (eval('' + (shi[ihi] + '</option>').split(vsl[ihi].trim() + sc).length) == 3) {
newih+=shi[ihi] + '</option>';
vssize++;
} else {
svalis=shi[ihi].split(' value="')[1].split('"')[0];
newih+=shi[ihi].split('>')[0].replace(svalis, vsl[ihi].trim() + sc) + '>' + vsl[ihi].trim() + sc + '</option>';
vssize++;
}
} else if (vsl[ihi].trim().indexOf('filter:') == 0) {
newih+='<option contenteditable=true value="' + vsl[ihi].trim() + sc + '">' + vsl[ihi].trim() + sc + '</option>';
vssize++;
} else {
newih+='<option contenteditable=true value="' + vsl[ihi].trim() + '">' + vsl[ihi].trim() + '' + '</option>';
vssize++;
}
}
}
if (!changefound) {
newih+='<option contenteditable=true value="Change">Change</option>';
vssize++;
}
oselo.innerHTML=newih;
if (eval('' + ssize) != eval('' + vssize)) {
oselo.size='' + eval('' + vssize);
}
}
return '';
}
โฆ and โฆ - in the image browsing helper we needed to allow for non animated GIF images, as we did for our new image_css_filter_display
html โfirst draftโ โImage Filter Displayโ web applicationโ
And so, onto yesterdayโs Animated GIF Duration Calculation Filter Browsing Tutorial we developed, today, achanged client_browsinghtm helper web application you can try for yourself as a standalone arrangement or have it get called via todayโschanged read_exif_off_image_rotate
php PHP image exif reporter web application.
Previous relevant Animated GIF Duration Calculation Filter Browsing Tutorial is shown below.
Can a โproof of conceptโ arrangement last three blog postings? If thereโs more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, and another iframe hosted web application joins in on โproof of conceptโ goings on and will be useful into the future, weโd say itโs possible, yes. But we would say that, wouldnโt we?!
In our defence, it is easier to prove all solutions to all the contentious issues, and then hone in and reduce to make a specific new web application, rather than extending and still needing to prove as you go along, not knowing whether an issue will cause you insurmountable issues in the future.
But they would say that, wouldnโt they?!
And so, continuing on from the recent Animated GIF Duration Calculation Filter Tutorial we considered another mode that a user might use on top of โฆ
- entering an image (animated GIF) URL into a textbox โฆ that being to โฆ
- browse for a local system (animated GIF) file (via File API)
โฆ getting us to call on changes to our โvia File APIโ specialist with achanged (with new data URI supporting Javascript) โฆ
var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false, isag=-1, isagname='';
function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1 || whatgifmaybe.indexOf('data:image/gif') == 0) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}
function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}
function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}
/** @param {Uint8Array} uint8 */
function isGifAnimated (uint8) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
//alert('' + duration);
var damore='', wpthere=false;
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
if (window.parent) {
if (window.self !== window.parent && parent.document.getElementById('aside')) {
wpthere=true;
parent.document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
parent.document.getElementById('aside').scrollIntoView();
parent.document.getElementById('image').style.opacity='0.5';
parent.document.getElementById('image').style.width='5%';
parent.document.getElementById('isub').style.opacity='0.5';
} else {
document.getElementById('aside').style.display='block';
document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
}
} else {
document.getElementById('aside').style.display='block';
document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
}
if (!wpthere) { document.getElementById('aside').scrollIntoView(); }
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
//} else {
//alert('duration=' + duration);
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}
โฆ client_browsinghtm helper web application you can try for yourself as a standalone arrangement or have it get called via todayโschanged read_exif_off_image_rotate
php PHP image exif reporter web application.
Did you know?
A quirk with our new HTML button element within an HTML form had us, initially, before realizing โฆ
- onmousedown event event.stopPropagation() usage can be used to cancel a following onclick event on non-mobile โฆ and โฆ
- ontouchdown (yay!!!) event event.stopPropagation() usage can be used to cancel a following onclick event on mobile
โฆ as in โฆ
<button title='Click or touch here, as required, for chance to browse for Animated GIF' ontouchdown='event.stopPropagation(); spagif();' onmousedown='event.stopPropagation(); spagif();'><sup>Animated</sup><sub>GIF</sub></button>
โฆ and could overcome the adverse โonclickโ based coding we had prior to the discovery. Thanks to javascript โ Does using event.preventDefault() in โmousedownโ prevent โclickโ or โmouseupโ event in jquery? โ Stack Overflow for the heads up about this.
Previous relevant Animated GIF Duration Calculation Filter Tutorial is shown below.
Can a โproof of conceptโ arrangement last two blog postings? If thereโs more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, weโd say itโs possible, yes. And so, continuing on from the recent Animated GIF Duration Calculation Primer Tutorial we tweak its PHP hosting โproof of conceptโ parent web application to try out our second point weโre out to prove โฆ
We want to prove that CSS filter works for animated GIFs as well as it appears to work with other image types of elements.
Conservative worry, we grant you, but we did want to make sure this all worked, and happily, it was all fine โฆ
var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false;
function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}
function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}
function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}
/** @param {Uint8Array} uint8 */
function isGifAnimated (uint8) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
var damore='';
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
document.getElementById('aside').innerHTML='<?php echo $image; ?> Animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
document.getElementById('aside').scrollIntoView();
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}
And so, especially because GIF images cannot be useful for exif information, it helps us isolate our โproof of conceptโ feel to todayโschanged read_exif_off_image_rotatephp PHP image exif reporter web application which we can supply an argument to such as the Katoomba Street Art Walk inspired one also shown below โฆ
Previous relevant Animated GIF Duration Calculation Primer Tutorial is shown below.
Weโve got a new (mini-?)project developing. No, it doesnโt hurt in the โyou know whatโ! But thanks for your concern?!
Itโs a project that reminds us about an adage regarding projects, that might seem pretty obvious, but is worth mentioning โฆ
Many projects being 90% perspiration, 10% inspiration, there might be the โnot sure we can doโ items that should be tackled first.
That truism is all well and good, but not always possible, of course, when you have to set up the difficult environment ahead of testing this unknown. Not so, with the โunknownโ of our new project โฆ
We want to know whether we can detect an animated GIF media file playing duration, ideally in client side Javascript, and if not possible there, we would settle for a server side PHP solution.
Happily (via our duration of animated GIF using Javascript Google search), yet again, the online wooooorrrrlllldd has come to our rescue via this excellent webpageโs Javascript ideas, so many thanks!
We slotted its thinking (and Javascript (via PHP) โฆ
function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}
/** @param {Uint8Array} uint8 */
function isGifAnimated (uint8) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
if (document.getElementById('aside')) {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF duration is ' + eval(duration / 100) + ' seconds)';
}
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}
... logic), you might say in a "kludgy" way (but, for us, serving a "proof of concept" purpose), that allows us to proceed on other aims of our project that will become apparent into the near future. No, we are not totally "out of the woods" yet regarding "unknowns" but today'schanged read_exif_off_image_rotatephp PHP image exif reporter web application) into the "onblur" logic of an image URL textbox HTML element, that web application talked about when we presented Gimp Guillotine Image File Browse Media Tutorial. You might try it yourself, but not sure "animated GIF and exif" mix, if you get my meaning, but if your image is an animated GIF you should be informed of its duration, in seconds, up the top of the webpage (given permissions and all, that is)?
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.