FusionReactor 9.2.1 update released

If you're using FusionReactor, note that a new 9.2.1 update was released last week, Jan 31, with a couple of bug fixes--including one where you may need to add a JVM arg to prevent an error, in a certain case as I will discuss. For more, read on. [More]

From: Charlie Arehart - Server Troubleshooting

New URL for signing up to the CFML Slack: cfml-slack.net

TLDR; the URL for joining the CFML Slack workspace and channels has changed. If you want to join the CFML Slack, use the form at cfml-slack.net. As some may have noticed, the old URL for joining (cfml-slack.herokuapp.com) no longer works. Since it's mentioned in many places on the web, I wanted to help spread this news. This cfml-slack.net URL replaces that, while the URL for the CFML Slack channel itself is unchanged: cfml.slack.com. For more explanation/context, and especially if you may be new to considering the CFML Slack, read on. [More]

From: Charlie Arehart - Server Troubleshooting

Links For You

Hey folks, I'm writing to you from another world. A world where I somehow got eight-plus hours of sleep two days in a row. Now, previously I would have told you this was a make-believe world, but now I know the truth, it exists. (And I'll just do my best to forget the nightmare I had a bit before I work up.) With that out of the way, here are a few links to start your week.TheJam.dev VideosI was privileged to speak at TheJam.dev last month, a free online conference covering the Jamstack. The sessions are slowly making their way to YouTube, and while mine isn't on there yet (I was the last session), I know it's coming soon. You can watch a good chunk of the presentations now and I've embedded the playlist below. I just bugged Brian and he let me know everything should be there by mid-week.The State of Developer ConferencesSpeaking of Brian, I wanted to share an article he wrote about the current state of conferences, nicely titled, "The State of Developer Conferences". As someone who both speaks at and runs conferences, he has a great perspective on how things have changed since COVID.As for myself... I just want to share what I've learned. I love to travel, and miss the fact that I don't do as much, but at the end of the day, I'll use whatever means necessary to reach folks and help. Between you and me, I've been posting more videos to YouTube lately, and while they're just short little snippets, I'm hoping it helps reach folks who prefer video content to writing.Eleventy Tip - Anchor Links and HeadersLast up is a great post by Rhian van Esch, "Adding heading anchor links to an Eleventy site". In this post, he describes a few options by which headers defined in Markdown can automatically become anchor links. I plan on adding this to my own blog in the next few weeks. Plus, the article is a good reminder that Markdown can be modified to support new features, and unsurprisingly, Eleventy makes it easy to do so.

From: Raymond Camden

Using JavaScript in a WebC Component

A week or so ago (time is so weird these days), I gave a presentation on Eleventy's WebC plugin. While working on the slides, I built a bunch of demos of various things and knew I'd share a few on the blog. Here's one in particular I wanted to write about. This isn't anything not covered by the docs, but like most things, I needed to try it myself first to see it in action. Specifically for this post, I want to talk about JavaScript in WebC components.Let's begin by creating a simple tag, cat, that will render a random cat:<template webc:type="11ty" 11ty:type="ejs"><%// credit:function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive}let width = getRandomInt(200,600);let height = getRandomInt(200,600);%><p class='myCatImage'><img src="https://placekitten.com/<%= width %>/<%= height %>"></p></template>The component uses EJS to generate a random width and height and then outputs it using the PlaceKitten image holder service. Not terribly useful, but it's cats, and cats always serve a purpose. If we add this to a page:<h2>Cats</h2><cat></cat><cat></cat>We will end up with two random cats. (Random at build time of course, once deployed it's going to be static HTML.) Here's a completely gratuitous screenshot just so I can have some cat pictures in the post:Ok, so far so good, but let's add a bit of interactivity to the component. I want to make it so that when you mouseover the picture, the browser plays a sound file of a cat meowing. I would never do this in real life because it would be annoying af as the kids say, but whatever. Here's the new version:<template webc:type="11ty" 11ty:type="ejs"><%// credit:function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min) + min); // The maximum is exclusive and the minimum is inclusive}let width = getRandomInt(200,600);let height = getRandomInt(200,600);%><p class='myCatImage'><img src="https://placekitten.com/<%= width %>/<%= height %>"></p></template><script>const meow = new Audio('meow.wav');document.addEventListener('DOMContentLoaded', () => { const catPics = document.querySelectorAll('.myCatImage img'); catPics.forEach(c => { c.addEventListener('mouseover', () => { console.log('over da cat'); /* You will get a DOMException if you don't click on the page first, which is good, but we also don't care about it, so try/catch and ignore */ try { meow.play(); } catch { // do nothing } }, false); });}, false);</script>The code basically just looks for cat images by class and adds the event listener. If we add this, and check our site, we'll get... nothing. If you view source, you'll see why:<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <title></title><script type="module" integrity="sha512-bSCWm+/TC6zrRk+5XcKszZefvT4Aqwa8b0XOmkMfIirtfzTRqgxEkpAurbYHXD+q0VGBS5e4C4U3XEuBeIOUrA==" src="/.11ty/reload-client.js"></script></head><body><body><h1>Cat Test</h1><cat><p class="myCatImage"><img src="https://placekitten.com/488/206"></p></cat><h2>Another Cat</h2><cat><p class="myCatImage"><img src="https://placekitten.com/405/204"></p></cat><h3>Hello</h3><cat><p class="myCatImage"><img src="https://placekitten.com/501/455"></p></cat></body></body></html>What happened to our JavaScript? Well, it turns out, WebC automatically detects this, and "gathers" up the JavaScript into one bundle you can use in your code. To use the bundle, you can add a bit of code to your layout:<script>{{ page.url | webcGetJs }}</script>This is Liquid code, but similar code exists for layouts written in WebC, and other languages. Once added, we get the correct behavior, and you can see it in source now:<!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"> <title></title> <script>const meow = new Audio('meow.wav');document.addEventListener('DOMContentLoaded', () => { const catPics = document.querySelectorAll('.myCatImage img'); catPics.forEach(c => { c.addEventListener('mouseover', () => { console.log('over da cat'); /* You will get a DOMException if you don't click on the page first, which is good, but we also don't care about it, so try/catch and ignore */ try { meow.play(); } catch { // do nothing } }, false); });}, false);</script><script type="module" integrity="sha512-bSCWm+/TC6zrRk+5XcKszZefvT4Aqwa8b0XOmkMfIirtfzTRqgxEkpAurbYHXD+q0VGBS5e4C4U3XEuBeIOUrA==" src="/.11ty/reload-client.js"></script></head><body><body><h1>Cats</h1><cat><p class="myCatImage"><img src="https://placekitten.com/477/484"></p></cat><cat><p class="myCatImage"><img src="https://placekitten.com/327/432"></p></cat></body></body></html>What's nice is, despite cat being run twice, only one copy of the code is used, which makes sense, but is still nice to see. And since the code is checking for multiple items matching the class, only one copy of the code makes sense.As an aside, you may not want WebC to bundle your code. If so, simply add webc:keep to your script tag, like so:<script webc:keep>// awesome code in here that's totally important for the user, totally.</script>Read more about this at the docs: Asset BundlingWant to play with this? You can see the code here, https://glitch.com/edit/#!/webc-javascript-example, or run the released version here, https://webc-javascript-example.glitch.me. Enjoy!

From: Raymond Camden

Dynamically Updating Views With Turbo Streams Using Hotwire And Lucee CFML

Ben Nadel explores the use of Turbo Streams to dynamically update views in a Hotwire and ColdFusion application....

From: Ben Nadel

My town sure seems to have a lot of...

Ok, so I realize this will make me sound old (spoiler, I am old), but I swear I feel like my town (Lafayette, LA) has about ten thousand or so storage businesses. And banks. Oh, and hotels too. For a while now I thought it would be interesting to see if I could build a tool that would actually do that - count the number of a type of business. This week I took a stab at it and while the results aren't perfect, it was fun, and that's all that matters, right?For my demo, I decided to use Google Map's Places API, or more accurately, that part of the JavaScript library. (Google's Maps APIs don't support CORS so if I wanted to do a direct call I'd need to setup a serverless proxy. Overkill for a dumb little demo.)The Places API supports a few different ways of searching, and for my first attempt I tried the Text Search version. This supports free form queries including things like, "banks lafayette, la", and I thought it would be a good way to start. I began with some simple HTML, asking for a type of business and a location:<p><label for="business">Enter a business type:</label> <input type="text" id="business" placeholder="car wash,storage place,etc"></p><p><label for="location">Enter a location:</label> <input type="text" id="location" placeholder="lafayette,la or washington,dc"></p><button id="searchBtn">So just how many are there?</button><div id="results"></div><div id="map"></div>I've got two form fields, a button, and then a div for the results. You'll notice I also have a div for a map. I'm not using a map, but the Google Maps JavaScript library requires a div for a map. Even if you don't show it. Seems a bit weird, but what's one more div between friends, right?Now let's consider the code. First off, the Google Maps JavaScript library is usually loaded via a script tag where the url includes your key, the libraries you need, and the name of a callback function. I was building on CodePen and that didn't quite work well. Instead, I simply appended a script tag to the end of my DOM using this:// Load Google Maps _after_ initMap setupvar script = document.createElement('script');script.src = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyCA0y7kh6V8poL-faDyVf3TpnLDNf9XtQY&libraries=places&callback=initMap';script.async = true;// Append the 'script' element to 'head'document.head.appendChild(script);I could have made that a nice function but I just dropped it at the end of my code. Now let's look at the function called by the library:function initMap() { console.log('initMap called'); let pyrmont = new google.maps.LatLng(-33.8665433,151.1956316); map = new google.maps.Map(document.getElementById('map'), { center: pyrmont, zoom: 15 }); service = new google.maps.places.PlacesService(map); $business = document.querySelector('#business'); $location = document.querySelector('#location'); $results = document.querySelector('#results'); $searchBtn = document.querySelector('#searchBtn'); $searchBtn.addEventListener('click', doSearch);}As I mentioned above, you must have a map div even if you don't plan on showing it. I created a Map object based on sample code from their docs and I've got zero clue where that latitude and longitude is. In the end, it doesn't matter as it won't be used. The rest of the code creates my service object and assigns some DOM elements to variables for use later.When the search button is clicked, doSearch is run:function doSearch() { console.log('doSearch'); $results.innerHTML = ''; let biz = $business.value.trim(); let loc = $location.value.trim(); if(biz === '' || loc === '') return; total = []; $results.innerHTML = '<p><i>Currently searching...</i></p>'; service.textSearch({ query: `${biz} ${loc}` }, handleResults);}I grab the values, do a bit of simple validation (the user has to enter something), and then call the text search API via the service object I created. Note how query is crafted from the user input.Now for the fun part, handling the results. Google's library supports pagination, and actually makes it quite easy to use. I defined total as an empty array in doSearch and it's global to the page. Here's how I use it:function handleResults(r, status, pagination) { console.log('results', r); console.log('pagination.hasNextPage', pagination.hasNextPage); let open = r.filter(b => { return b.business_status === 'OPERATIONAL'; }); total = total.concat(open); if(pagination && pagination.hasNextPage) pagination.nextPage(); else { console.log('total total is ', total.length); let finalResult = `<p>I found a total of ${total.length} results. Remember the max is 60.</p><p>`; total.forEach(t => { finalResult += `${t.name}, ${t.formatted_address}<br/>`; }); $results.innerHTML = finalResult; }}As I said, the service handles pagination well. When I call nextPage(), it automatically knows to run handleResults again. So all I need to do is keep adding to the total array (but only after filtering out closed businesses) and when done, render out to HTML.As you can see in the text, there's a max of 60, which is unfortunate, because even in our mid-sized town, there's a crap ton of results for some of my searches. Still though it was kind of fun. For our town, searching for church returns the max, searching for bar returns 56. But I think it would have been 60 too if I didn't have the filter for closed businesses. Test it out yourself here: See the Pen Testing Places API (2) by Raymond Camden (@cfjedimaster) on CodePen.So that was round one. Let's make it simpler. The Google Places API also supports a Nearby Search operation. This lets you pass in a location and a business type, where the types are a nice long list of, well just about everything. In my second version, I switched my HTML to a drop down:<p><label for="business">Select a business type:</label><select id="businessType"></select></p>Which is populated via JavaScript:const TYPES = [ 'accounting', 'airport', 'amusement_park', 'aquarium', 'art_gallery', 'atm', 'bakery', 'bank', 'bar', 'beauty_salon', 'bicycle_store', 'book_store', 'bowling_alley', 'bus_station', 'cafe', 'campground', 'car_dealer', 'car_rental', 'car_repair', 'car_wash', 'casino', 'cemetery', 'church', 'city_hall', 'clothing_store', 'convenience_store', 'courthouse', 'dentist', 'department_store', 'doctor', 'drugstore', 'electrician', 'electronics_store', 'embassy', 'fire_station', 'florist', 'funeral_home', 'furniture_store', 'gas_station', 'gym', 'hair_care', 'hardware_store', 'hindu_temple', 'home_goods_store', 'hospital', 'insurance_agency', 'jewelry_store', 'laundry', 'lawyer', 'library', 'light_rail_station', 'liquor_store', 'local_government_office', 'locksmith', 'lodging', 'meal_delivery', 'meal_takeaway', 'mosque', 'movie_rental', 'movie_theater', 'moving_company', 'museum', 'night_club', 'painter', 'park', 'parking', 'pet_store', 'pharmacy', 'physiotherapist', 'plumber', 'police', 'post_office', 'primary_school', 'real_estate_agency', 'restaurant', 'roofing_contractor', 'rv_park', 'school', 'secondary_school', 'shoe_store', 'shopping_mall', 'spa', 'stadium', 'storage', 'store', 'subway_station', 'supermarket', 'synagogue', 'taxi_stand', 'tourist_attraction', 'train_station', 'transit_station', 'travel_agency', 'university', 'veterinary_care', 'zoo' ];// later in the code...$businessType = document.querySelector('#businessType');let optionsString = TYPES.reduce((s, t) => { return s + `<option>${t}</option>`;}, '');$businessType.innerHTML = optionsString;I just want to go on record as saying I've now used reduce twice this week and I'm definitely now a leet coder. Or lute coder? Whatever.I then removed the address and simply got your location via geolocation:let location = await getLocation();// later in the code...async function getLocation() { return new Promise((resolve, reject) => { navigator.geolocation.getCurrentPosition(pos => { resolve(pos.coords); }, e => { reject(e); }, { enableHighAccuracy: true}); });}I love using async/await to "patch" over old APIs like geolocation and make them a bit nicer to use. The final change was to switch to the Nearby API:service.nearbySearch({ location: mylocation, radius: 1609, type: [biz]}, handleResults);The radius value is in meters and 1609 is roughly equal to a mile. Here's a screen shot of in action:I'm sharing a picture and not embedding CodePen because geolocation is blocked when embedding the CodePen. I checked, and as far as I know there's no workaround, so for now, you'll need to click a link, sorry about that: https://codepen.io/cfjedimaster/pen/MWBZJWZLet me know what you think. Keep in mind, the results are based on the data Google has, and it's not always going to be accurate. I know I saw things in my test that were incorrect.

From: Raymond Camden

Working Code Podcast - Episode 112: Listener Questions

Ben Nadel and the crew respond to listener questions ranging from alternate realities to dead body disposal....

From: Ben Nadel

Authentication Bypass Vulnerability in Mura CMS and Masa CMS – Preliminary Security Advisory

Multiple versions of Mura CMS and Masa CMS contain an authentication bypass vulnerability that can allow an  unauthenticated attacker to login as any Site Member or System User. The post Authentication Bypass Vulnerability in Mura CMS and Masa CMS – Preliminary Security Advisory appeared first on ColdFusion.

From: Adobe Coldfusion Blogs

A Simple Slide Show Using Hotwire And Lucee CFML

Ben Nadel builds a simple slide show with Hotwire Turbo Drive and Lucee CFML. This defers all dynamic rendering to the ColdFusion server....

From: Ben Nadel

Cloudinary Debugging Tip

I've been blogging about Cloudinary here for the past few months, and I wanted to share a quick tip. A few weeks ago, I was privileged to be interviewed on the Cloudinary podcast, Dev Jams:While showing some code, I came across an image being loaded by Cloudinary that was returning a broken image. Obviously I'd done something wrong, but what? I began by opening the image in a tab, but that just gave me a 400 error:Turns out - there's a simple way to get to the issue. Open up your browser devtools and switch to the Network tab. Click on the request and go into the response headers. Scroll down until you see x-cld-error, and you'll have your error message there:You'll notice it's also present in server-timing, but x-cld-error is the clearer message. Hope this helps!

From: Raymond Camden

Senior Developers vs Master Developers

We need to do away with the term senior developer in the software industry. Here is why I propose we start using the term Master Developer.

From: Steve Neiland: Blog of a Web Developer

OnRequestStart() / OnRequest() Methods Invoked Even If Requested Template Doesn't Exist In Lucee CFML

Ben Nadel discovers that the onRequestStart() and onRequest() ColdFusion application event handlers get called in Lucee CFML even if the requested template doesn't exist....

From: Ben Nadel

Setting Up My ColdFusion + Hotwire Demos Playground

Ben Nadel creates a Dockerized ColdFusion and Hotwire playground in which he can explore the Hotwire framework from Basecamp....

From: Ben Nadel

Quick WebC Tip

Whenever I think I shouldn't post something because I'm covering something completely obvious, despite the fact that I missed it, I always find at least one other person who was also a bit slow in either remembering a basic tip or figuring out the simple stuff. So hey, that one person, good morning, and I hope this helps.Alright, so if you are using Eleventy's new WebC feature, or starting to learn it, one of the first things you'll do is create a .webc file in your editor. However, you may notice you don't get the nice formatting you are used to in your editor. Here's a screenshot from Visual Studio Code:I was playing around with WebC for a few weeks before it really clicked with me that I wasn't getting proper formatting, or code hinting. Luckily it's easy enough to fix. In Visual Studio Code, open up your File Association settings. And then add *.webc as an html file:After that - voila:You also get your expected code hinting and such which is useful of course. While this particular example is for Visual Studio Code, any decent editor would support a similar configuration as well.

From: Raymond Camden

Easily Implement UUIDs as Primary Keys in Spring Boot 3

In this tutorial you will learn how to use one of the new features in Jakarta EE 10 in a Spring Boot 3 application.

From: Dan Vega

cfqueryparam sql injection

I’ve searched the docs but cannot seem to find an answer to “Does using the cfqueryparam prevent SQL Injection”?  Found some info while googling but would like a definitive answer from this community. Thanks! The post cfqueryparam sql injection appeared first on ColdFusion.

From: Adobe Coldfusion Blogs

Be aware that ColdFusion 2018 end-of-life (and end of updates) is coming July 2023

Are you still running ColdFusion 2018? Did you know that its end-of-life is July 13, 2023? That's the date that "core" support ends--meaning, no more updates from Adobe after that, not even security fixes. As for CF2021, it gets updates into 2025, and the currently running pre-release of CF2023 is a great sign for the continued vitality of CF. But this looming deadline for CF2018 is a reminder that as the years roll on, we not only get new versions but we must say good-bye to old ones. Wondering what you can do? or when CF2021 or CF2023 support will end also? And what's the difference between "core" and "extended" support Adobe sells? (The extended support plan does NOT provide updates beyond this coming July.) For more on these, including official Adobe documentation that discusses such things, as well as my thoughts on migration, costs, various options to consider, and more, do read on. [More]

From: Charlie Arehart - Server Troubleshooting

Thrilled to be presenting at Devnexus 2023

I'm thrilled to announce that I've been selected as a speaker at Devnexus 2023, the long-running professional developer conference held in Atlanta. If you may not be familiar with it, I'll talk about the event a bit more below, as well as offer a discount code to attend. As for my session, it will be "Transitioning to Java 17 from 11 or 8 for Admins": [More]

From: Charlie Arehart - Server Troubleshooting

Working Code Podcast - Episode 111: How To Learn Stuff Good

Ben Nadel and the crew talk about the strategies that we use when we have to learn totally new thing (and how humbling that experience can be)....

From: Ben Nadel

Modernize or Die® – CFML News Podcast for January 24th, 2023 – Episode 181

Gavin Pickin and Brad Wood host this week’s CFML News Podcast To listen or subscribe to the podcast visit our site Or watch the video replay on youtube:  They discuss a the latest Java 8, 11, 17 and 19 releases, and a gotcha you might not realize with the Oracle JDK installers. Webinars / Meetups and Workshops – Ortus Fridays back in January 2023 including Grant Copley talking about CBWire as well as a poll on the Ortus Community site […] The post Modernize or Die® – CFML News Podcast for January 24th, 2023 – Episode 181 appeared first on ColdFusion.

From: Adobe Coldfusion Blogs

What's new in FusionReactor 9.2.0, released Jan 18 2023

If you're a user of the wonderful FusionReactor monitoring and observability solution (for ColdFusion, Lucee, Java servers and more), you may delight in hearing news of a new FusionReactor (FR) version. 9.2.0 was released last week, Jan 18, 2023. You can learn more (in brief) about what's new in the bullets for 9.2.0 offered at the release notes page. TLDR: For some folks, news of the new version is all the need to hear. For those who may like to hear a bit more about the update, read on. [More]

From: Charlie Arehart - Server Troubleshooting

Beware that latest Oracle JDK installers will REMOVE older JDK installs of that version

Here's something new to beware if you may run the Oracle JDK installer for the recently updated Java 11 or 17, whether on Windows, macOS, or via RPM: the new Oracle jdk installer WILL REMOVE any older previous versions of that JVM version created by previous JDK installers of the same major version. (Note that this issue does not affect those who implement java by extracting it from a compressed file, like a zip or tar.gz.) Update: Since I posted this last night, I've heard some people assert "this is not new behavior: Java's always popped up and offered to remove old versions". Those folks are misunderstanding something: that was true of past JRE installers (like in Java 8 and earlier, which don't exist for Java 11), but it was never the case for Oracle JDK installers (even for Java 8). THAT's what's new about the JDK 11 and 17 installers, and it's DOCUMENTED in the release notes, as I discuss below. But it may surprise those who never saw a JDK installer do that, thus this post. (The rest of this post remains unchanged.) I'm referring here to new behavior in the JDK installers from the Jan 2023 update, which I blogged about recently. This topic will apply also to subsequent JVM updates as they come out in the future. (Fortunately for some, this issue does NOT affect those running Java 8 or below, or Java 19 or above, as I will explain.) While the technotes for the new updates (which I point to in my post above) do make mention of the issue I'm describing, I don't feel they do it in as obvious a manner as they might (it's not clear how it affects CURRENTLY installed earlier updates of JDK 11 or 17)., and I've already helped some people dealing with the ramifications of the change. And of course it's all the MORE important to make sure this is made known to those who might NOT read the release notes. I've also found that the JDK installer doesn't ALWAYS warn that there are running processes using the older JDK version that it's about to remove. And to be clear, it won't warn about applications that are NOT running but which are configured to try to use the older JDK version that would be removed. Read on for: The issue, in brief: JDK installers now implement a single-minor-version-per-major-version policy, deleting older JDK installations The implications of this changed behavior which may trip you up--and a solution Some closing considerations [More]

From: Charlie Arehart - Server Troubleshooting

Does The Order Of Hash Inputs Matter In Terms Of Uniqueness And Distribution?

Ben Nadel explores the impact of input order when hashing values in ColdFusion....

From: Ben Nadel

Comparing Java's MessageDigest To ColdFusion's hash() Function In Lucee CFML

Ben Nadel compares Java's MessageDigest class to ColdFusion's hash() function for hashing compound / composite binary values....

From: Ben Nadel

Using "continue" To Short-Circuit .each() Iteration In ColdFusion

Ben Nadel shares a quirk of the CFML language in which "continue" can be used to short-circuit an .each() iteration function....

From: Ben Nadel