Content Developer II at Microsoft, working remotely in PA, TechBash conference organizer, former Microsoft MVP, Husband, Dad and Geek.
132341 stories
·
29 followers

In Search of My Next Role

1 Share

This week I discovered, unfortunately, that my position at Adobe has been eliminated. I'm incredibly proud of what I've achieved during my time at Adobe, but now need to find my next opportunity. If you've ever gained anything from one of my posts, or presentations, I'd absolutely love a recommendation or referral for a position in developer relations. I'm also looking for a role where I could mentor, or lead, a team of developer advocates/evangelists. So, if you know of a role, or have a role yourself, please reach out!

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Links For You (12/14/24)

1 Share

Good morning folks, as I shared yesterday, this week has been a bit rough as I found out my job was eliminated at Adobe, but the outpouring of support, and links to jobs, has been overwhelming. You people are pretty darn good, you know what? I'm confident I'm going to be able to land a good job, but at the same time, it's going to be a heck of a lot less stressful once I actually do. On top of that, I've got a head cold, which is annoying af as the kids say, but, I'm alive, surrounded by people who love me, well fed and warm, so all things considered, I'm pretty dang lucky. Let's get to the link.

AI in the Browser - A Playlist

A month or so ago, and I'm having trouble finding the link, Google hosted a one day conference on AI in the browser, covering things like Transformers.js, Tensorflow, and their own efforts to add AI natively to Chrome. The playlist for the conference is available and it's got some great content. Each one is relatively short and can be watched over a lunch break, and I definitely recommend checking it out. I'm only about half way through myself, but plan on finishing it soon.

A-Maze-ing JavaScript

Next up is a fun one, generating random mazes with JavaScript, by Paul Hebert. His post goes into the details of generating mazes, something that's fascinated me for years, although the last time I did anything in this space was with ColdFusion way back in 2009: Generating mazes in ColdFusion. Hebert's post does a great job of breaking down the steps and explaining the code.

You can play with a finished demo below:

See the Pen Random Maze Generator by Paul Hebert (@phebert) on CodePen.

Cooking with Eleventy

Last up is look at adding Cooklang support to Eleventy: Adding Cooklang Support to Eleventy Three Ways. As the title says, Robb demonstrates three different ways to add Cooklang, a recipe markup language in Markdown, to Eleventy. As I've said before, one of Eleventy's many strengths lies in it's customizability, and this is a superb example of that.

I currently use Saffron for my recipes, and while it's a very nice app, I'm almost at the limit of the free tier, and while I think the app has value, I'm don't think I'm going to pay the subscription fee to upgrade (if I could do a one time purchase I'd consider it). I've been thinking for a while now about moving my recipes to a simple web site. I talked about using Saffron's output way back in 2022, Use Your Saffron Recipes in the Jamstack, but I think I may look at converting Saffron's output to Cooklang instead. When I have time. Ahem.

Just For Fun

One of the reasons my wife and I use Spotify so much is music discovery. We'll put on a favorite song, let it finish, and often Spotify will riff into things we like, and things we've never heard of. A few days ago, Spotify suggested "Indie Frequency", a playlist of new indie songs from black artists. Sadly, I don't think I recognized more than one artist on this list. Happily, it was damn good.

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Links For You (12/28/24)

1 Share

Welcome to the last Links For You for 2024. Believe it or not, I started this series way back in April of 2022, and I don't know about you, but it's been one of my favorite features of my blog. I love sharing cool links (and music videos!) with readers, and I hope yall have enjoyed it as well. This is my second to last post for the year so there's still a bit more content coming, but for now, let's get into the cool stuff!

An Alpine.js Bluesky RSS Reader

Folks know I love Alpine.js, and this first post is a great example of why. Andy Jarrett demonstrates how he built a RSS reader of his Bluesky profile using Alpine.js. It's relatively simple to do so, and one of the reasons I think Alpine.js is so great is that it's a lightweight addition to your web page, versus heavier options like React and Vue.

JavaScript's Nullish Coalescing Assignment Operator

I'll be honest with you. I can't always remember all the "special" operators JavaScript has. Once again, this is a good reminder about why I tend to fail code tests in interviews. (And I'm fine with that.) In this post, Trevor Lasn explains the nullish coalescing operator (??=) and how you can use it in your code.

This is explained better in the post, but to be clear, this operator is not the same as the nullish coalescing operator. One is always going to assign a value and one (the nullish coalescing assignment operator) will only assign if the value is currently null. Take my word for it, just read the post.

Destructuring in JavaScript

Last up is another JavaScript post, this one focused on destructuring: "A guide to destructuring in JavaScript". This is a fairly intensive guide to destructuring filled with loads of examples. I thought I knew this topic pretty well but I definitely ran into a few things I did not know, so once again, this is well worth your time.

Just for Fun

Last but not least, how about a freaking music video built in CSS and HTML? Yes, just when you thought you couldn't fall behind in how awesome CSS has become, here's a great example!

See the Pen CSS Music Video - No Images - Pure Code. by Ben Evans (@ivorjetski) on CodePen.

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Building a Bluesky AI Sentiment Analysis Dashboard

1 Share

As the "Great Social Network Wars" carry on (my term, not anyone else), I'm finding myself more and more enjoying Bluesky. I do more posting on Mastodon, but Bluesky reminds me a lot more of early Twitter. Threads is... ok, but has felt too corporate. I can't even remember the last time I checked it. Earlier this week, I was poking around the Bluesky API and was incredibly happy to discover that their Search API does not require a key and supports CORS, which means a simple client-side application could make use of it. In the past I had built similar tools for Twitter, back when it had a decent API, and I thought it might be fun to build something for Bluesky, specifically, a way to monitor sentiment of keywords in real time. Here's what I created.

What the App Will Do

At a high level, the app lets you:

  • Enter a keyword to check
  • On a schedule, get recent posts for that keyword
  • For each post, analyze the sentiment of the text
  • Get and return an average
  • Optionally let the user delete the keyword from the dashboard

For my app, I kept it incredibly simple, and ugly, and there's a number of UI/UX things that could be improved, but let's look at how I got it together.

The Search API

The first thing I did was play a bit with the Search API. It contains multiple different arguments but at minimum, requires a search query.

As a minimum example, this will return posts with my name:

https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=Raymond+Camden

The top level result is an array of posts. Here's two as an example:

{    "uri": "at://did:plc:mw7drluj7dtqybvzkcqkworx/app.bsky.feed.post/3lelx76yjxb2u",	"cid": "bafyreidgtoclrufosj6x6bqd3yxlqgtgrwvgo2m4ulmb7j4qc4scqtciha",	"author": {		"did": "did:plc:mw7drluj7dtqybvzkcqkworx",		"handle": "florianrappl.bsky.social",		"displayName": "Florian Rappl",		"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:mw7drluj7dtqybvzkcqkworx/bafkreig7q5kols7gwkz3ey524nuiws73s2knkn6lcj7ir3lbvnczki5xxi@jpeg",		"labels": [],		"createdAt": "2024-11-23T08:57:28.845Z"	},	"record": {		"$type": "app.bsky.feed.post",		"createdAt": "2024-12-31T11:32:55.067Z",		"facets": [			{				"features": [					{						"$type": "app.bsky.richtext.facet#link",						"uri": "https://www.raymondcamden.com/2024/12/18/summarizing-with-transformersjs"					}				],				"index": {					"byteEnd": 106,					"byteStart": 34				}			}		],		"reply": {			"parent": {				"cid": "bafyreifx3dzyzrzknjcdo3hgk5mx3fphmn3wiuuauq4xvk4ixdobbetbyq",				"commit": {					"cid": "bafyreihoieerqoxprnlqn46j3a3efleazasmsh4gzpdcijspj7fhjdl6au",					"rev": "3lelx752qn32d"				},				"uri": "at://did:plc:mw7drluj7dtqybvzkcqkworx/app.bsky.feed.post/3lelx752gul2d",				"validationStatus": "valid"			},			"root": {				"cid": "bafyreifx3dzyzrzknjcdo3hgk5mx3fphmn3wiuuauq4xvk4ixdobbetbyq",				"commit": {					"cid": "bafyreihoieerqoxprnlqn46j3a3efleazasmsh4gzpdcijspj7fhjdl6au",					"rev": "3lelx752qn32d"				},				"uri": "at://did:plc:mw7drluj7dtqybvzkcqkworx/app.bsky.feed.post/3lelx752gul2d",				"validationStatus": "valid"			}		},		"text": "Summarizing with Transformers.js (https://www.raymondcamden.com/2024/12/18/summarizing-with-transformersjs) by Raymond Camden"	},	"replyCount": 0,	"repostCount": 0,	"likeCount": 0,	"quoteCount": 0,	"indexedAt": "2024-12-31T11:32:55.845Z",	"labels": []},{	"uri": "at://did:plc:zha3q6pd5zhbr7dmgp25b3x5/app.bsky.feed.post/3lczlj4cy5k23",	"cid": "bafyreicjkluug5pg4waj7dmakmygpzxbelxhnvk3b2vepqxhbly35iwafa",	"author": {		"did": "did:plc:zha3q6pd5zhbr7dmgp25b3x5",		"handle": "codepo8.bsky.social",		"displayName": "Chris Heilmann",		"avatar": "https://cdn.bsky.app/img/avatar/plain/did:plc:zha3q6pd5zhbr7dmgp25b3x5/bafkreie35iy2fwn25ufakobqmqko4dnveyl2d47ijzx55kbc73gbbvczjq@jpeg",		"labels": [],		"createdAt": "2023-06-17T10:17:43.112Z"	},	"record": {		"$type": "app.bsky.feed.post",		"createdAt": "2024-12-11T10:50:36.582Z",		"embed": {			"$type": "app.bsky.embed.video",			"aspectRatio": {				"height": 1920,				"width": 1080			},			"video": {				"$type": "blob",				"ref": {					"$link": "bafkreiex2dxpm4xbsmqk6d7zx7n3dnclufdowso52woj6odss5vj2oadqy"				},				"mimeType": "video/mp4",				"size": 963604			}		},		"langs": [			"en"		],		"text": "Proof that @wearedevelopers live events are really live and that Raymond Camden is a trooper…"	},	"embed": {		"$type": "app.bsky.embed.video#view",		"cid": "bafkreiex2dxpm4xbsmqk6d7zx7n3dnclufdowso52woj6odss5vj2oadqy",		"playlist": "https://video.bsky.app/watch/did%3Aplc%3Azha3q6pd5zhbr7dmgp25b3x5/bafkreiex2dxpm4xbsmqk6d7zx7n3dnclufdowso52woj6odss5vj2oadqy/playlist.m3u8",		"thumbnail": "https://video.bsky.app/watch/did%3Aplc%3Azha3q6pd5zhbr7dmgp25b3x5/bafkreiex2dxpm4xbsmqk6d7zx7n3dnclufdowso52woj6odss5vj2oadqy/thumbnail.jpg",		"aspectRatio": {			"height": 1920,			"width": 1080		}	},	"replyCount": 0,	"repostCount": 0,	"likeCount": 2,	"quoteCount": 0,	"indexedAt": "2024-12-11T10:50:38.652Z",	"labels": []}

The API supports pagination parameters, but for my usage, a default set of 25 items felt like a good enough sample size. As you can see, quite a bit of data is returned, but for each post, you can get to the text via the record.text key. I did add one parameter to my search code, and that was adding lang=en, to focus on English. Modify or remove that if you need to. Here's a minimal code sample in JavaScript:

let topic = 'python';let req = await fetch(`https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=${encodeURIComponent(topic)}&lang=en`);let data = await req.json();

Getting Sentiment

To perform the sentiment analysis, there's a large variety of options here, but I really wanted to stick to client-side code only. For me that would come down to two options, Transformers.js or Chrome's new built-in AI functionality. I first covered Transformers.js a few weeks ago, Using Transformers.js for AI in the Browser, and I really liked how easy, and usually quick, sentiment analysis was done. With that in mind, I decided on Transformers.js.

The App

Ok, so as a warning, this isn't terribly pretty, but let's take a look at the app. In HTML, it's rather simple, a place to enter keywords, a status div, and a results div:

<p><label for="newTopic">Enter New Topic: 	<input id="newTopic"></label> <button id="addTopic">Add Topic</button></p><div id="results"></div><div id="status"></div>

Most of the work is done in JavaScript, and while I'll share the complete demo below, let me share the pertinent bits. The code to handle adding a topic is basic DOM manipulation, adding a string to an array of topics called, topics. In my startup routine, I do handle loading in and storing my core Transformers.js model:

$status.innerHTML = 'Loading sentiment analyzer...';classifier = await pipeline('sentiment-analysis');$status.innerHTML = '';

The important part is the actual analysis which is done on a schedule. That core function is below:

async function checkTopics() {	console.log('checkTopics');	if(topics.length === 0) return;	$status.innerHTML = 'Loading Bluesky data for topics.';	let responses = [];	topics.forEach(t => {		responses.push(getSentiment(t));	});	console.log('fired off calls for each topic');	let results = await Promise.all(responses);		console.log('all done', results);	$status.innerHTML = '';	renderResults(results);	setTimeout(checkTopics, INTERVAL);}

I basically fire off calls to my analysis function and store the resulting promise in an array, and when done, pass the results off for rendering.

Here's how I get the sentiment:

async function getSentiment(topic) {	console.log(`Get sentiment for ${topic}`);	let sentimentTotal = 0;		let req = await fetch(`https://public.api.bsky.app/xrpc/app.bsky.feed.searchPosts?q=${encodeURIComponent(topic)}&lang=en`);	let data = (await req.json()).posts;	console.log(`Posts found: ${data.length}`);	for(let i=0; i<data.length; i++) {		let sentiment = (await classifier(data[i].record.text))[0];		//console.log(`Sentiment for ${data[i].record.text} is ${JSON.stringify(sentiment)}`); 		if(sentiment.label === 'NEGATIVE') sentiment.score = -1 * sentiment.score;		sentimentTotal += sentiment.score;	}	let avgSentiment = sentimentTotal / data.length;	console.log(`Total sentiment, ${sentimentTotal}, avg ${avgSentiment}`);	return { topic: topic, sentiment: avgSentiment, total:data.length,  generated: new Date() };}

Basically, hit the Bluesky search API, and for each result, I call my classifier object and add the result to a total I can do an average on. Each result contains a label, POSITIVE or NEGATIVE (in theory, NEUTRAL is possible too, but I never saw it). Each result also has a score, which is always positive, but I flip it negative so that in theory, my average will range between -1 and 1. I also return a bit of metadata in the result like the orignal topic, how many items were found, and when it was generated.

The last bit, the rendering, is fairly simple. The only real oddity here is that it's possible for someone to remove a topic while analysis is happening, so I did a quick check to remove that if it happens.

function renderResults(results) {		/*	It's possible a user clicks remove while we were loading 	stuff, so we'll do a quick sanity check.	*/	results = results.filter(r => topics.includes(r.topic));		let s = '';	results.forEach(r => {					s += `			<div class="result" data-topic="${r.topic}"><h2>Sentiment Analysis for: ${r.topic}</h2><p>Average was <strong>${r.sentiment>0?'POSITIVE':'NEGATIVE'}</strong> (Average Score: ${r.sentiment} over ${r.total} items)<br>Generated: ${dateFormat(r.generated)}</p><p><button class="removeBtn" data-topic="${r.topic}">Remove from Analysis</button></p>			</div>`;	});	$results.innerHTML = s;	document.querySelectorAll('button.removeBtn').forEach(d => {		d.addEventListener('click', removeItem);	});}

I've embedded the complete application below, but you can also open up the live demo here: https://codepen.io/cfjedimaster/live/jENaEMV.

See the Pen BS Search Panel by Raymond Camden (@cfjedimaster) on CodePen.

Everything Wrong...

That's a scary heading. ;) So, there's quite a bit that could be improved here to make this a nicer dashboard. I had considered using Shoelace to make it prettier, and that would be great I think. Also, I'd like to add a proper list of topics being checked so you can see them all the time, remove, add, etc. Right now if you add X as a topic, you won't actually see it till the first result is returned. Users may think it's broken, so that's not good.

But - my biggest question is - does anyone find this useful? I'd absolutely be willing to put some love into this and launch it as a proper web app, but I'd like to know first if folks would actually use it. ;) Leave me a comment below!

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

See What WebAssembly Can Do in 2025

1 Share
An open box with a star atop it is encircledd with various lines coming out from it to symbols representing growth and trends to watch.

WebAssembly (Wasm) is a compiler on steroids, as I described it a few years ago, irking many proponents. But I would argue that description still holds true, as hopefully by 2025, WebAssembly modules will be able to integrate applications written in the language of your choice deployed across any environment or device running a compatible CPU instruction set. This would enable simultaneous deployment and updates of applications across diverse device types.

Once a niche project at Mozilla to a technology integrated across various environments and infrastructures, WebAssembly has grown significantly over the past few years and is in use across various industries.

Early discussions at talks at KubeCon and conferences like WasmCon and Wasm/IO attracted only a few hundred attendees. In contrast, recent events at these and other conferences such as KubeCon+CloudNativeCon have been progressively more packed with attendees actively using and developing WebAssembly, reflecting its increasing relevance in open source communities.

Looking ahead to 2025, it’s anticipated that WebAssembly will see some real adoption beyond the sandbox projects presented at conferences (which are fascinating, more often than not). It may be still be difficult to explain its functionality to laypersons, but there will be more real-world examples showing what Wasm can do as its applications are expected to expand into not only from the browser, but to the server, serverless computing, edge deployments and other areas. In some cases, WebAssembly may replace traditional containers and integrate directly with Kubernetes. Then there are the security aspects of WebAssembly that have attracted the attention of the U.S. government.

The Final Mile?

One of WebAssembly’s main features hasn’t been realized yet: a standardization so that applications written in any language that can be distributed through Wasm modules for deployment on any endpoint simultaneously — and asynchronously. Once finalized, a component model will enable WebAssembly to expand its use beyond web browsers and servers. It will allow users to deploy different applications running inside numerous lightweight modules at very high speeds across thousands of endpoints simultaneously.

Much depends on the finalization of a component model and especially its relationship to WASI, which is the standard interface or API linking the WebAssembly modules to the components. It will support the development of so-called WebAssembly “Worlds,” as groups of compatible Wasm components form an interconnected infrastructure similar to Kubernetes, but without containers. WASI Preview 2, released in 2024, made some huge strides toward standardization, but we are not there yet.  In 2025, we will likely not achieve the Holy Grail, but we could see some pleasant surprises.

Improved WASI and component standards means more languages that can be used with WebAssembly beyond the current stable of Rust, Go and C++.

“In 2025 we need to see tight integration between the WebAssembly System Interface (WASI)  and Python, so that every Python developer can write apps that work in Wasm,” Torsten Volk, an analyst at TechTarget’s Enterprise Strategy Group, said. “This integration is so exciting as it would enable developers to just write reusable Python modules that other developers can pop straight into their own apps. Eliminating the age-old issue of developers continuously recoding already existing programs would be a significant breakthrough in developer productivity.”

Once finalized as soon as in 2025, a component model will enable WebAssembly to not just see its expanding use beyond web browsers and servers, but will be able to allow users to deploy different applications running inside numerous lightweight modules. They are distributed at very high speeds across a few to thousands of endpoints simultaneously through the component interface called World without changing one iota of code, as mentioned above.

Also, as mentioned above, the component model will also enable Wasm to integrate more programming languages.

“From the first day it was announced, WebAssembly’s big gamble was on language support. It’s one thing to build a standard binary format, and it’s altogether different to get dozens of programming languages to compile to that format — yet that’s what has happened with Wasm,” Matt Butcher, Fermyon co-founder and CEO, said. “The component model, though, is what takes this binary format to a new level.”

With the component model, a Python developer can use libraries written in Rust and a JavaScript developer can leverage existing Go libraries,” Butcher said. “It no longer matters what the source language was — merely that it was built into a Wasm component.”

Micro VMs for Edge

The idea of using Wasm modules to serve as lightweight and sandboxed security for edge deployments and management has been around for a while. Called different things depending on the cloud vendor, micro VMs  will allow for on-premises or cloud sources to distribute massive amounts of data traffic coming from on-premises systems through the cloud. This is done through very light Wasm modules compared to containers.  Microsoft, GoogleCloud, and others will offer different variations as the standard is worked out in 2025.

“We can now process network traffic as it enters the system using these lightweight sandboxes,” said Mark Russinovich, CTO and technical fellow of Microsoft Azure, speaking at the Microsoft Ignite user conference. “This opens up incredible possibilities for real-time, efficient network processing.”

Wasm modules will not replace containers completely, but they will be gradually integrated in cloud native environments to fill in many of the gaps lacking with traditional containers and VMs.

Volk said these will move from the least efficient deployment type — VMs — to the most efficient one —WASM containers — with standard Linux containers being the middle ground.

“I see organizations running VMs, containers and Wasm containers side by side, with Kubernetes acting as the puppet master that takes care of policy compliance, resilience and performance,” Volk said.

In many ways, WebAssembly serves as the missing puzzle piece for deploying and managing network edge devices.

“We are so used to thinking in terms of client and server that edge caught us off guard. It broke us out of our mold,” Butcher said. “With Wasm’s ability to run in just about any environment, our old two-tier client-server model is giving way to a continuum of computing. Edge computing is the keystone of Wasm’s success, and we will see that on full display in 2025.”

Security is a Real Thing

WebAssembly’s capacity to not only be secure for applications but also serve as a measure of security for applications has been shown to be effective in research papers and other studies over the past few years. However, it hasn’t yet gained significant traction as a standalone security measure.

In 2024, according to a U.S.-government National Institute of Standards and Technology (NIST) paper, “A Data Protection Approach for Cloud-Native Applications,” released earlier this year, WebAssembly could and should be integrated across the cloud native service mesh sphere in particular to enhance security. The framework outlined in the paper may lead to future compliance requirements for WebAssembly or cloud native environments, while also setting the stage for broader use of WebAssembly for security in general.

My prediction is that while we probably won’t see widespread adoption of WebAssembly as a security measure in 2025, this report will likely initiate or prepare the groundwork for serious consideration of how WebAssembly can serve as a security layer, particularly for cloud native applications. So, while WebAssembly may not be required for compliance with U.S. government projects in 2025, it could eventually become a key component in the future.

“Wasm’s tight security can prevent sufficient resource access for many workloads,” Volk said. “But here the Wasm contributors and product vendors have their work cut out for them, as they can prioritize their roadmaps based on what companies are running on standard Linux containers in real life.”

The post See What WebAssembly Can Do in 2025 appeared first on The New Stack.

Read the whole story
alvinashcraft
1 hour ago
reply
West Grove, PA
Share this story
Delete

Microsoft to spend $80 billion in FY’25 on data centers for AI

1 Share

Microsoft has earmarked $80 billion in fiscal 2025 to build data centers designed to handle artificial intelligence workloads, according to a company blog post. Specifically, the tech giant plans to build out AI-enabled data centers “to train AI models and deploy AI and cloud-based applications around the world.” Of that $80 billion allocation, more than […]

© 2024 TechCrunch. All rights reserved. For personal use only.

Read the whole story
alvinashcraft
2 hours ago
reply
West Grove, PA
Share this story
Delete
Next Page of Stories