Managing coldfusion-out.log and log rotation in ColdFusion

ColdFusion provides a built-in logging system to help you track and troubleshoot application issues. The logging system generates various log files, including the coldfusion-out.log file, which logs standard output and errors. However, if left unmanaged, the coldfusion-out.log file can grow very large and consume a lot of disk space. In addition, it can become difficult to find relevant log entries in a large log file. Therefore, it is important to manage the coldfusion-out.log file and implement log rotation to keep […] The post Managing coldfusion-out.log and log rotation in ColdFusion appeared first on ColdFusion.

From: Adobe Coldfusion Blogs

Configuring MultiSubnetFailover for Microsoft SQL Connection String in ColdFusion 2021

If you’re using ColdFusion 2021, you’ll be happy to know that the ColdFusion 2021 offers built-in support for multiSubnetFailover. This means you can configure your Microsoft SQL database connections to failover quickly and efficiently, with minimal impact on your applications and users. Below are the simple steps: Step 1: Log in to ColdFusion Administrator and navigate to Data & Services > Data Sources page. Choose “Other” as the driver type and Enter a name for your data source Step 2: […] The post Configuring MultiSubnetFailover for Microsoft SQL Connection String in ColdFusion 2021 appeared first on ColdFusion.

From: Adobe Coldfusion Blogs

Interesting Caveat with Web Components and the Event Lifecycle

I've been exploring web components the last few months and as part of that exploration, I've been reading "Web Components in Action" by fellow Adobian Ben Farrell. I'm still at the beginning of the book but so far it's been great. It is a few years old now, but for the most part, the only thing I've seen out of date is that at the time of publication, Microsoft Edge didn't have complete support for web components yet. That's been corrected (good thing, I switched to Edge a while back) so it's not really a concern.However yesterday I read something that didn't quite jive with my understanding. The fourth chapter, "The component lifecycle", deals with the various hooks you get into web components when they are used on a page. In this chapter, he spends a good amount of time comparing the constructor of a web component to the connectedCallback event. The constructor is called when the component is created, but connectedCallback is not fired until the component is added to the browser's DOM. That last bit is important. If you add an instance of a web component to a DOM element, let's say a div you created in JavaScript, but that div itself is not in the browser's DOM, the event won't fire.Before going further, let's look at a quick example. Assume this JavaScript for a trivial component:class MyComponent extends HTMLElement { constructor() { super(); console.log('constructor called'); this.innerHTML = '<h2>My Component</h2>'; } connectedCallback() { console.log('connected callback called'); }}if(!customElements.get('my-component')) customElements.define('my-component', MyComponent);If we use <my-component> in the DOM, we will see both console messages for each instance of the tag. Here's a CodePen that demonstrates this. Note that you will need to "Edit on CodePen" to actually see console messages, or open your console right here on my site. See the Pen WC Tests by Raymond Camden (@cfjedimaster) on CodePen.All of this made sense, and really touched on something I've been noodling over - what should I put in the constructor versus connectedCallback. He made one point that didn't seem right to me - that if you check the value of an attribute in the constructor, it will be null. I've been doing this in my previous examples, and heck, even MDN shows it in one of their examples:class PopUpInfo extends HTMLElement { constructor() { // Always call super first in constructor super(); // Create a shadow root const shadow = this.attachShadow({mode: 'open'}); // Create spans const wrapper = document.createElement('span'); wrapper.setAttribute('class', 'wrapper'); // stuff deleted... // Take attribute content and put it inside the info span const text = this.getAttribute('data-text'); info.textContent = text; //lot more stuff...Here's an example where it clearly works just fine:class MyComponent extends HTMLElement { constructor() { super(); console.log('constructor called'); if(!this.getAttribute('title')) this.setAttribute('title', 'No title'); } connectedCallback() { console.log('connected callback called'); this.innerHTML = `<h2>My Component: ${this.getAttribute('title')}</h2>`; }}if(!customElements.get('my-component')) customElements.define('my-component', MyComponent);And if called like so:<my-component title="ray"></my-component><my-component></my-component>I get:My Component: rayMy Component: No titleAs I said, this matched my expectations. Here's a complete CodePen for this: See the Pen WC Tests (2) by Raymond Camden (@cfjedimaster) on CodePen.So, Ben and I talked about this over Slack, and initially, we just figured it was a change since he released his book, but then he made a really important point. What happens if you create an instance of your component via JavaScript? Consider:class MyComponent extends HTMLElement { constructor() { super(); console.log('constructor called'); if(!this.getAttribute('title')) this.setAttribute('title', 'No title'); } connectedCallback() { console.log('connected callback called2'); this.innerHTML = `<h2>My Component: ${this.getAttribute('title')}</h2>`; }}if(!customElements.get('my-component')) customElements.define('my-component', MyComponent);let mc = document.createElement('my-component');document.body.appendChild(mc); In this case, I've made a new my-component and added it to my DOM. I would have assumed this just worked, but instead, you get an error:Uncaught DOMException: Failed to construct 'CustomElement': The result must not have attributesIf you want to see this yourself, open up this CodePen, and open your browser's console, not the CodePen one. The error doesn't get floated up right to the 'virtual' console CodePen uses.Now it makes sense, and it's an easy enough correction to move that logic to connectedCallback:class MyComponent extends HTMLElement { constructor() { super(); console.log('constructor called'); } connectedCallback() { console.log('connected callback called'); if(!this.getAttribute('title')) this.setAttribute('title', 'No title'); this.innerHTML = `<h2>My Component: ${this.getAttribute('title')}</h2>`; }}if(!customElements.get('my-component')) customElements.define('my-component', MyComponent);And in doing so, I can then create instances in JavaScript, and even set my title:let mc = document.createElement('my-component');document.body.appendChild(mc); let mc2 = document.createElement('my-component');mc2.setAttribute('title','Custom title');document.body.appendChild(mc2); In the CodePen below, you can see I used both a "regular" instance of the component in HTML as well as the two defined here and all three act correctly: See the Pen WC Tests (3) by Raymond Camden (@cfjedimaster) on CodePen.I hope this makes sense, and as always, reach out if it doesn't. Going forward, I'll be doing more of my attribute validation and setting in connectedCallback.

From: Raymond Camden

Working Code Podcast - Episode 117: Champions Of Truth

Ben Nadel and the crew recap their Two Truths and a Lie choices and crown a single champion of truth from our listeners....

From: Ben Nadel

Styling Submit Buttons During Form Submission With Hotwire And Lucee CFML

Ben Nadel demonstrates how to alter a submit button's appearance and text content using the "data-turbo-submits-with" in Hotwire and ColdFusion....

From: Ben Nadel

Installing JDK 11.0.18 on server removes all other JDK 11 installations

A change of behavior in the Oracle JDK 11 installer deletes previously installed JDKs and overwrites the most recent version. The post Installing JDK 11.0.18 on server removes all other JDK 11 installations appeared first on ColdFusion.

From: Adobe Coldfusion Blogs

Adding a Chart to an Apline.js Application

For a while now my blog queue has had an item in there suggesting I take a look at adding a basic chart to an Alpine.js application. I finally got a chance to play around with this over the weekend and I thought I'd share the result. For this post, I've used Chart.js, which is a free, open-source charting library that's relatively easy enough to use. Certainly, others could be used as well and as always, if you've got an example, I'd love to see it. With that out of the way, let's take a look at the application.Before the ChartI'll start by sharing what I built before I added a chart to the display. This application consists of a list of cities. For each city, we use the Pirate Weather API to get an hourly forecast and from that, I display the temperature over the next twelve hours. Here's how that looks:I probably should have included a timestamp but for now, this gets the point across. Let's take a look at the code. I begin by defining my cities. This probably would be dynamic, loaded from a database or API, etc.cities: [ { label: "Lafayette, LA", latitude: 30.22, longitude: -92.02 }, { label: "Bellingham, WA", latitude: 48.768, longitude: -122.485 }, { label: "Chicago, IL", latitude: 41.881, longitude: -87.623 }, { label: "Washington, DC", latitude: 38.895, longitude: -77.036 } ]When the application starts, I want to fire off requests to get forecasts. I did this in two methods. The first top-level method fires off the requests:async getForecasts(locs) { console.log('get forecasts for my locations'); let requests = []; locs.forEach(l => { requests.push(this.getHourlyForecast(l.latitude, l.longitude)); }); let data = await Promise.all(requests); data.forEach((d, i) => { this.cities[i].forecast = d; }); this.numForecasts = this.cities[0].forecast.length;},Here I make use of promises to fire all four requests at once and then wait for them to finish. Yes, I should have error handling here. The result of Promise.all will be one array item per promise and will be in the same order I created them, so I can assign the results to my cities by just looping over them.The actual API call is done here:async getHourlyForecast(lat, lng) { let req = await fetch(`https://api.pirateweather.net/forecast/${APIKEY}/${lat},${lng}?exclude=alerts,daily,currently,minutely&units=us`); let data = await req.json(); return data.hourly.data.slice(0,12);}I pass in my API key and the location to the API. The result contains a lot of information, but all I want is the hourly records and only the first twelve. I could probably simplify the result even more but this is good enough.With the forecast information ready, the table can now be displayed. Here's the UI:<div x-data="app"> <table> <thead> <tr> <template x-for="city in cities"> <th x-text="city.label"></th> </template> </tr> </thead> <tbody> <template x-for="i in numForecasts"> <tr> <template x-for="city in cities"> <td x-text="city.forecast[i-1].temperature"></td> </template> </tr> </template> </tbody> </table></div>Basically one loop over the cities to build the table header, and then a loop over the number of forecasts with an inner loop over each city to build each row.Here's a CodePen demonstrating the complete application. See the Pen Alpine + ChartJS (Initial) by Raymond Camden (@cfjedimaster) on CodePen.Adding the ChartFor my chart, I thought it would be nice to visualize both the highest and lowest temperatures for each of the cities. That would give us an idea of the range over our time period as well as the relative difference in warmth between the cities. (Spoiler - Louisiana is hot. Always hot.) Here's the chart I came up with:Note that this was me doing the bare minimum in terms of "design". Chart.js seems really powerful and I could absolutely do more to make this prettier, but honestly, it works, and I was pleased with how quickly I got this working. Here's what I had to do.First, I added the library, https://cdn.jsdelivr.net/npm/chart.js. And hey, thank you Chart.js for not forcing me to npm anything. I appreciate it.Next, I added a canvas to my HTML. Because I'm lazy, I used the same ID as their docs, but this can be changed of course.<canvas id="myChart"></canvas>Next, I added a new method to my code, renderChart, to handle the process. Here's that code.renderChart() { const ctx = document.getElementById('myChart'); let names = this.cities.map(c => c.label); let highestTemps = this.cities.map(c => { return c.forecast.reduce((highest,f) => { if(f.temperature > highest) return f.temperature; return highest; },0); }); let lowestTemps = this.cities.map(c => { return c.forecast.reduce((lowest,f) => { if(f.temperature < lowest) return f.temperature; return lowest; },999); }); new Chart(ctx, { type: 'line', data: { labels: names, datasets: [ { label: 'Highest Temp', data: highestTemps, borderWidth: 1 }, { label: 'Lowest Temp', data: lowestTemps, borderWidth: 1 } ] }, options: { scales: { y: { min: -20, max: 120 } } } }); }Let's examine this. The very first line simply gets a reference to the canvas tag where Chart.js will do its work. The next few lines of code are all me "prepping" my data for the chart. First I get a list of cities. Then I get both the highest and lowest temps for each city with the crafty use of both map and reduce. I am a JavaScript master and I will absolutely pass the next arbitrary coding challenge I get for a job interview. Honest.The net result of the above three blocks of code is three arrays. Each of these can then be passed to my chart declaration. You'll see names passed in for the labels and then my two datasets. This is all pretty much boilerplate demo code from Chart.js, the only thing I did custom was to specify a scale for my Y-axis. My range there isn't perfect, I know some places were below negative twenty recently, but it works for now.You can demo this version here: See the Pen Alpine + ChartJS (Chart) by Raymond Camden (@cfjedimaster) on CodePen.Some Quick NotesOk, all of the following does not actually apply to the main point of this post, but I had some thoughts about what I built and wanted to share them.First, I'm still relatively new to Alpine and still trying to figure out the "best" (for me) way to work with it. I like that Alpine is flexible in its definition and lets you specify methods and data all at once. That being said - I'm not sure I'm happy with how I organized my code. I think my feeling is that I should use the following rules:Put the init() method on top.Put any and all simple variable declarations next.Put methods after.Second, you may or may not notice I added a simple cache to the forecast function in the second CodePen. I did this to ensure I didn't kill my access to the API as CodePen tends to rerun stuff quite a bit. (I need to disable that I think. I just did. Will remember for next time. Honest.)

From: Raymond Camden

Rendering A Persistent Dismissible Banner Using Hotwire And Lucee CFML

Ben Nadel demonstrates how to create a persistent dismissible site-wide banner in a Hotwire enhanced ColdFusion application....

From: Ben Nadel

Links For You

Good morning readers! I'm writing this in a hotel room in Tuscaloosa where my wife and I are visiting our son. He was presented with a significant award a few nights ago (the Algernon Sydney Sullivan award) and we stayed up a few extra days. We're about to head back to Louisiana so I thought I'd share a few quick links with folks. Have a great Sunday.Taking Eleventy into the Spiderverse with eleventy-fetchHere's a great post by Jeff Sikes where he describes how he made use of the Marvel API in an Eleventy site. That's mixing two of my favorite things, Marvel and Eleventy! I really wish Marvel would continue working on their API. The last update was nearly a decade ago, but on the other hand, I'm happy they just didn't shut it down.Eleventy Collection SchemasYet another awesome Eleventy tip from Stephanie Eckles, this post documents an Eleventy plugin for enforcing your frontmatter setup in Eleventy collections. This is really a good idea since Eleventy gives you complete freedom over your frontmatter, being able to enforce certain rules in your site will help prevent issues in your site. Heck, I made a mistake with my frontmatter a few weeks ago and this would have really helped!Frontend Development Projects with Vue 3 - Second EditionAbout a year or so ago I was involved in the writing of a Vue 2 book for Packt, and now that book has been updated for Vue 3 by myself and Maya Shavin. I have to say - I've been kinda... not again... but not terribly excited about Vue lately. That being said, having used Vue 3 (obviously) for working on this book, I'm feeling somewhat better about it. I still don't think Vue is going to be my framework of choice going forward, I really prefer Alpine, but for any "application", I'd definitely build it in Vue 3.You can get the book from Packt here, https://www.packtpub.com/product/frontend-development-projects-with-vuejs-3-second-edition/9781803234991, or if you buy from Amazon here I'll get an Amazon Associates kickback. Either way, check it out and let me know what you think.

From: Raymond Camden

Dynamically Adding Stimulus Controllers To Static Content Using Hotwire And Lucee CFML

Ben Nadel demonstrates that Stimulus controllers can be dynamically applied to static content served up by a ColdFusion server....

From: Ben Nadel

The User Experience (UX) Of Disabled Form Buttons

Ben Nadel discusses the user experience (UX) of disabled form buttons; and why it's a violation of the Robustness Principle....

From: Ben Nadel

Standalone Components in Angular

import(`./subsection/subsection.module`).then( m => m.SubsectionModule ) } ]; The module would have to load all components, providers, and could even include it's own router. I always found this to be a lot of boilerplate code just to implement lazy loading. Now with a standalone component, we can make it simpler, which I love. First, let's create a simple routes that does not include lazy loading. Open up the app-routing.module.ts file: const routes: Routes = [ { path: 'view1', component: WrapperComponent }, { path: '**', redirectTo: 'view1' } ]; The first route is named view1, and points to WrapperComponent. I also added a catch all route, distinguished by the two asterisks in the path. The catch all route redirects to the view1. Now, open up app.component.html: Remove this and replace it with the router outlet: With this approach, we can remove the component import from the app.module.ts. Instead of this: imports: [ BrowserModule, AppRoutingModule, WrapperComponent ], We can just do this: imports: [ BrowserModule, AppRoutingModule ], Recompile the app, and load it in the browser: You can see the route in the browser at view1. Start typing to make sure it all works: All good to go; so, we've proved that the stand-alone components are working fine with the router. But, the use of the router here mirrors what we did in the main books, which did not investigate lazy loading at all. How do we set up lazy loading of the module? Back to the app-routing.module.ts and replace the view1 route with this: { path: `view1`, loadComponent: () => import(`./wrapper/wrapper.component`).then( m => m.WrapperComponent ) }, The syntax is very similar to the lazy loading segment I shared earlier. Instead of a loadChildren() method, we now use a loadComponent() method. The value is an arrow functions. The arrow function uses the import command to load in the component. The import returns, surprisingly, a promise. We resolve the promise with the then() method, and the result handler returns the component. You can re-run the app right now to see that it is continuing to work, but to see the real power of lazy loading, let's create another route and view. Let's create a new component: ng generate component view2 --standalone You'll see something like this: We're not going to implement a lot of functionality in the View2Component, only using it to link between the two respective views. Take a look at the default view2.component.ts: import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-view2', standalone: true, imports: [CommonModule], templateUrl: './view2.component.html', styleUrls: ['./view2.component.css'] }) export class View2Component { } To tell Angular to link between routes, we'll need to load in the RouterModule as part of the imports configuration: imports: [CommonModule, RouterModule], And don't forget the TypeScript import: import {RouterModule} from "@angular/router"; Open up view2.component.html. Replace all the contents with a link back to View1: Goto View1 For View2Component that's all we need. Let's go back to View1 which is powered by WrapperComponent. First, we'll need to tell it about the RouterModule in the component config imports: imports: [CommonModule, DisplayComponent, EditComponent, RouterModule], Don't forget the TypeScript import: import { RouterModule } from '@angular/router'; This is the same as what we did in the View2Component. We'll made a similar addition in the wrapper.component.html: Goto View2 I added a link to view2 in front of the other two components in the WrapperComponent. Now, open up the app-routing.module.ts. I'm going to show you the two cases, and how the browser interacts differently. First, with no lazy loading setup: const routes: Routes = [ { path: 'view1', component: WrapperComponent }, { path: 'view2', component: View2Component }, { path: '**', redirectTo: 'view1'} ]; Run the app, and take a look at the network console: Click in the browser between the two views and you'll notice nothing changes in the network tab. Everything is loaded all at once. Now, let's switch back to lazy loading in the app-routing.module.ts: const routes: Routes = [ { path: `view1`, loadComponent: () => import(`./wrapper/wrapper.component`).then( m => m.WrapperComponent ) }, { path: `view2`, loadComponent: () => import(`./view2/view2.component`).then( m => m.View2Component ) }, { path: '**', redirectTo: 'view1' } ]; We've already explored the view1 route and the catch all redirect route. This includes a view2 route, which loads the View2Component. Now reload the app in the browser and review the network tab: We load most of the same files. One thing you'll notice is that main.js is a lot smaller. And there is also a an additional js file loaded, which corresponds to the WrapperComponent. The end result is that we have less data loaded on the initial app load--which means your users are using the application much quicker. Click over to View2: I didn't clear out the network tab before clicking, but primarily you see View2Component loaded, but not until we clicked on the link to load that view. It is beyond the scope of this article to go into the benefits and specifics of lazy loading, but let's just say I love this use case for stand-alone components, because it is something that clearly removes a lot of boilerplate. Final Thoughts I learned a lot by exploring this post, and writing the chapter in my book. I hope you learned a lot reading it. I'm not sure how I feel about standalone components yet, but I do see them as a one way to make Angular applications easier to build, especially around lazy loading. I also see a lot of potential using them in libraries, where you want to optimize a component for reuse. If you've gotten this far, thank you for reading. Be sure to check out the bonus book from the Learn With Series on Angular 15 , which includes a more in depth version of this post with more samples including using services with standalone components, bootstrapping an application without using a module, and learning how to test stand alone components.

From: Jeffry Houser's Blog

Transcluding A Form Into A Turbo Frame Using Hotwire And Lucee CFML

Ben Nadel demonstrates one way to handle post-submission redirects when transcluding a form into another page. This uses Turbo Streams to "visit" multiple content areas of parent page....

From: Ben Nadel

Supporting PDF Embeds in an Eleventy WebC Component

Way back in the old days, in August of 2021, I wrote up an example of adding support for Adobe's PDF Embed API as an Eleventy plugin: "An Adobe PDF Embed Plugin for Eleventy". When I find time, I need to update that to the newest URL for the library, but more recently I was curious if I could recreate support using the WebC template language. While it was a bit difficult at times (and a big thank you goes to Zach for patiently helping me), I think it's at a point now where it can be shared. I will warn folks that I'm still struggling a bit with the best way to work with WebC, and at least one feature I'm showing isn't documented yet (but I've confirmed it will 100% ship), but hopefully this example will be useful for folks.Before we start, know that if you want to try this yourself, you will need a free credential. Credentials are host-based, which means a credential for raymondcamden.com will not work for localhost. You can definitely create a few, and if you really want to use one key for development and production, consider setting the host for your domain, minus the www, and use dev dot your domain locally. If you've never used your local hosts file for something like this, reach out and I'll help explain it. (Or heck, that may be my next post.)Alright, so I began actually by writing a template that called my component. I kinda figured I'd write the example code in what felt like the most logical manner, and then I'd actually build the WebC component to match it. Here's how I did it:<pdfembed width="700" height="600" clientid="912a3ba447664592bfbffb224b74a371" pdf="https://static.raymondcamden.com/images/2023/03/cat.pdf"></pdfembed>I've got two attributes to define the size of my PDF, my client credential (it's host-based, so safe to share here, go ahead, steal it, I won't tell), and then the URL for my PDF. Note that when you point to a PDF, it needs to be in a CORS-accessible location. You can also use file promises in the API, but I'm keeping it simple here.Now let's look at the actual component:<template webc:is="noscript"><a :href="pdf"><span @text="pdf"></span></a></template><div :id="uid"></div><script webc:keep src="https://documentservices.adobe.com/view-sdk/viewer.js"></script><template webc:type="11ty" 11ty:type="liquid">{% assign pdfname = pdf | split:"/" | last %}<script webc:keep>let clientID = "{{ clientid }}";document.addEventListener("adobe_dc_view_sdk.ready", () => { let adobeDCView = new AdobeDC.View({clientId: clientID, divId: "{{uid}}"}); adobeDCView.previewFile( { content: {location: {url: "{{pdf}}"}}, metaData: {fileName: "{{pdfname}}"}, focusOnRendering: false });});</script></template><script webc:is="style" webc:type="js" webc:keep>`div#${uid} { width: ${width}px; height: ${height}px;}`</script>Let's discuss. I begin by adding a noscript tag that links to the PDF. That way a user without JavaScript enabled will still be able to get to the document. In order for this to work in WebC, I couldn't use the noscript tag directly but had to use a template instead with the webc:is directive. Zach explained why... but I honestly don't quite get it. Not yet anyway.Next, note the div:<div :id="uid"></div>This is the part not yet documented. Every instance of a WebC component will automatically get provided a unique ID. This is especially useful for me as I need a way to associate a unique ID with the PDF library. This ID is safe for DOM IDs so it made sense to use it.Now for the slightly more complex part. I switch to Liquid so I can be a bit dynamic. Our library has a weird thing where it requires a URL (or file promise) as well as a PDF file name. I've already requested we get rid of this requirement, but for now, I get it by simply popping off the last part of the URL.The rest of the code in that Liquid block just outputs boilerplate PDF Embed code for the library and uses variables for the div ID, the PDF URL, and the filename.The final part is probably the most confusing. I needed to apply CSS to style the size of the div where the PDF is rendered. To do so, I used a JavaScript string literal. I'm using a script tag as, technically, it's JavaScript, but it comes out as CSS, so I map it with webc:is as I did on top. Again, thanks go to Zach for this tip. Finally, I need to use webc:keep because the default behavior in WebC is to toll up and bundle all JavaScript and CSS. In this case, I need the block to stay and be used in every particular instance I call the component.Whew. Hopefully, this made some sense. If you want to test this yourself, I made a Glitch, because Glitch is freaking cool. You can see it here: https://glitch.com/edit/#!/impossible-early-system?

From: Raymond Camden

Working Code Podcast - Episode 116: State Of Developer Conferences

Ben Nadel and the crew talk to Brian Rinaldi about the state of developer conferences; and, why post-pandemic attendance appears to be struggling both online and in real life....

From: Ben Nadel

Long-Term Funding, Update #1

As part of Clojurists Together's Long-Term Funding for 2023 I talked about working on clojure-doc.org which I had resurrected a few years ago, as a GitHub Pages project, powered by Cryogen.

From: Sean Corfield: An Architect's View

Update to My Eleventy Blog Guide

Last January, I announced the release of a guide I had written for building a simple blog in Eleventy. Now that Eleventy has hit 2.0, I took some time this morning to look at the guide and see what could be updated. The first thing I noticed was that I had a heck of a lot of typos. I fixed those. I then went through the two main versions of the blog (before and after UI was added) and updated the dependencies to the 2.0 release of Eleventy.That being said, I didn't do anything else. This is not to say that the 2.0 release wasn't lacking in new features, but as my guide is meant to be as simple as possible, I wasn't on the lookout to add any new features if it didn't make sense for the blog. Of course, one of the big features of 2.0 is a big reduction in dependencies, so right away people will benefit from it.Anyway, you can find the guide here: https://cfjedimaster.github.io/eleventy-blog-guide/guide.html.And you can find the repository here: https://github.com/cfjedimaster/eleventy-blog-guide.Feedback is always welcome!

From: Raymond Camden

Creating Custom Turbo Stream Actions In Hotwire And Lucee CFML

Ben Nadel demonstrates how to create a custom Turbo Stream action that can provide ColdFusion with ways to update the user experience....

From: Ben Nadel

My First Bug

I've told this story a few times before, but I don't think I've actually ever shared it on my blog. My interest in and introduction to computers came at a very early age. My mother's employer sent her home with an Apple 2 (either the Plus or E model, I forget which), and while it was supposed to be for her, it also included a bunch of games, so I immediately became attached to it. At around the same time, I saw a movie that had a huge impact on me. No, not Star Wars, but instead, TRON. While I was pretty young, I definitely knew it was fiction, and working with computers wouldn't be quite that cool, but it really fired up my interest. I mean, just look at this...So at some point, I stopped playing the games (err, well, stopped playing the games exclusively) and took a stab at trying to learn to program. Applesoft BASIC was a simple language, and best of all, you could literally turn on your machine and immediately begin writing programs. It's hard to describe just how exciting that was - having a development environment as a default meant I spent a heck of a lot of time writing programs. Shoot, I'd sometimes write the same simple program multiple times just to see the result again.My manual was the Applesoft BASIC Programming Reference Manual:This was a good manual, but I quickly ran into an issue, and by quickly I mean on page 2. Here's where I got stuck:BASIC programs consist of lines of code preceded by line numbers. By default, execution will go from the lowest number to the highest, but basic jumping around was supported as well. The typical program would use line numbers counted by ten. This lets you "slip in" lines of code you may have forgotten. Never complain about writing code in Notepad again - this was truly old-school coding. (And to be fair, it was a hell of a lot better than using punch cards. I'm old, but not that old.)Anyway, I followed that text very carefully, and when I ran it, I got an error. Here it is recreated in the Windows AppleWin emulator:I swear I looked at this for hours (most likely it was far less than that) and I just couldn't figure it out. I'd look at the manual, look at the screen, go back to the manual, and I just had no clue.Then... I went back to the manual, and read past the lines of code...See that highlighted line? Yeah, young Ray didn't notice it. I had entered the first line of code... and then used the spacebar to wrap the cursor to the next line.Dumb, right? Of course, with a few years of developer relations and technical writing experience, I look at that and immediately think I'd have moved that statement above the lines of code to make it more obvious.Getting it right gave me such a feeling of complete and utter joy. It's that feeling that has had me hooked on writing code.Luckily, I've not made that same dumb mistake since. I've made huge numbers of other, more unique dumb mistakes. I look forward to what I'll screw up next!Photo by Neringa Hünnefeld on Unsplash

From: Raymond Camden

Async Communication Is Great, Except For When It's Awful

Ben Nadel breaks down different types of asynchronous communication; and why one form - consensus building - is awful and should be avoided....

From: Ben Nadel

Including Inline Turbo-Stream Actions In Hotwire And Lucee CFML

Ben Nadel demonstrates that inline Turbo Stream elements will be processed by Turbo Drive in a Hotwire and ColdFusion application....

From: Ben Nadel

Persisting An IFrame-Based Video Player Across Page Visits With Hotwire And Lucee CFML

Ben Nadel creates a persistent IFrame-based video player in Hotwire and Lucee CFML by injecting a Turbo Frame before the Body tag....

From: Ben Nadel

Working Code Podcast - Episode 115: Self-Care For Developers

Ben Nadel and the crew talk about mental health and self-care. And, Adam opens up and shares much of what he's been going through lately with his ADHD....

From: Ben Nadel

Debloat Windows 11

Perform the following at your own risk. Microsoft does not support this program, which is maintained by an individual I do not know personally nor know their reputation well. It is recommended to perform this cleanup only after a clean install. Using this after customizing or installing programs may end with undesired consequnces, such as […]

From: Chris Tierney