Flow Like A Developer

Share with


Description

Salesforce Flows are becoming increasingly powerful, enabling Admins, Architects, and Developers to write automations typically reserved for Apex. In this session at DevOps Dreamin’, Matt Pieper, Director of Enterprise Engineering at LeafLink, showcases how to get the most out of your Flows. Learn how to take principles from the pro-code side and apply them to your Flows to elevate them to the next level.

Learn more:

Transcript

All right. Thanks, everybody, for joining me. I know it's post lunch. I'll do the best to stay entertained. I also feed off of energy. So please give it to me, and I'll give it back in return. So right now we're going to talk about flow like a developer.

I'm Matt Pieper. I'm a director of enterprise engineering at a company called LeafLink. For those of you who follow me on leaf LinkedIn, yes, that is Salesforce swag. I am not a hater. That is a trailblazer sweater right there. I do occasionally wear it.

So why is this guy on stage?

I started off my career as a software engineer, traditional product engineering, Python and Rails. And then one day someone said, hey, we have this thing called Salesforce.

Can you help us out? So my entire career has been within engineering in one way or another. But what I really like is how we can empower our low code and no code and non pro code engineers. How do we get that best ROI out of our environments? Because it really is that important.

The important thing is, yes, I have been an admin. I've been a solo admin. I have worn all the hats. Oftentimes when I come into orgs, I'm also an admin and having to clean up things or implement things that other admins can do.

So I am familiar with Flow. I mean it from time to time. But when I'm not talking about Salesforce, big photographer, like to travel. I'm a foster dog parent.

We're also a failure of that foster dog, so Oscar has been with us for eight years. And for those who care, I have non zero amount of certifications. I do have certifications. You can look them up if you want to know which ones they are.

So why flow like a developer?

It's an easy answer.

You are a developer. If you're writing any low code or no code automation, whether that's Flow, whether that's Zapier, whether that's Mule, you're actually doing what developers do day in and day out. The difference is where I might use words and long lines and functions and methods, you're using a flow canvas. At the end of the day, if you've not seen it, that giant XML is really what your flow is doing.

Right? You're taking that, an engine's parsing it, and then it's performing the same actions that we would as an Apex developer. Right? You're doing DML operations.

You're doing loops. You're interacting with that core database, and you're providing a UI element to your users.

It's also nice to learn new things.

Software engineering has been around for a while. We've built a lot of paradigms outside of just Salesforce, and we can use those same resources and patterns within Flow and other low code automations to really bring everybody together and start talking that same language and having a really robust SDLC process.

Also, I pointed this out here because every single time you look at code, I just notice this. I have a mistyped piece here, so that's awesome. That is how you flow like a developer. You have a typo, and then you run it, and then you scream into the void because you don't know why it's not working.

Have a plan, and then plan to change it.

There's lots of cliches out there. Right? You know, Patton, you know, your first plan survives until the enemy, yada yada yada. No different in engineering.

Raise your hand if this has ever happened to you. You get a feature out there. You get super excited. You're like, man, this is gonna be awesome.

I can knock this out in, like, five to ten minutes. You sit down in front of your computer, and your hand just start typing away. You know, you're moving that mouse. You got the flow canvas and then you go, crap.

I'm stuck because I didn't think about this edge case. And now you have to go back and delete things and restart.

That's where the plan comes in.

We have those requirements, but now it's time to design.

You know, the other cliches. Right? If Abraham Lincoln, if I have to chop down a tree, right, I'm gonna spend I have six hours to do it. I'm gonna spend five hours sharpen my ax. Don't believe everything you read on the Internet is true. Quoted by Abraham Lincoln, same sentence.

But it's really true. Right? The more we plan, the more we sit out ahead of time, the better off we are in the long run. Why?

Because it's not just us. Right? We have our peers that we can go and look at these plans. We can send these out to our stakeholders.

They can poke holes in our logic and make sense. Does this make sense? It also serves as that end user documentation for when you ship that feature. You have it in place.

All those assumptions were there. Those decision points were there.

It doesn't matter what tool you use. If you wanna use Figma, whether you're using a Miro, whether you want to use, draw dot io, whether you want to use pen and paper, whether you want to use a Google whiteboard, I recommend always just sitting down and starting to diagram that out, especially with flow because you have that framework that you can sit there and literally draw that flow to what your diagram would be.

And then my favorite is pseudocode.

Looks like a lot of text, but this really comes out in plain sentences to say, what am I doing? Right?

This flow is going to run on my opportunity update.

Five days from now, if something happens, I'm going to check it.

We're going to perform some other actions. Then I'm going to log something.

And if the update fails, I'm going to log that error.

You can hand this off to almost any individual in the world, even if they're not an engineer, even if they've never touched Salesforce.

And they can logically read through this and say, yeah, your logic checks out.

It's plain English, so that means you can type it and write it. You don't have to sit there and worry about any paradigms. And there's really no rules. Right? It's whatever makes sense to you so that as you're sitting and writing your flow, you can refer back to this.

So that's planning. That was really quick. Right? Like, I guess I should have probably been twenty minutes of the thirty minute, demo. But anyway, control your flow. Don't let it control you.

These emails are bad.

You should never get these emails. We call these unhandled exception alerts. Why are they called that? Because we didn't think about it. And we said, cool. We ran this thing, and an error happened. And oh, crap.

Why? Probably because we had a plan, for starters, or he missed a step, or, you know, a user just did something random that we had no idea that anybody would think about ever in their life. And I love those users. Find them. Hug them. Bring them into your UAT team. Let them break stuff.

But horrible.

If you get these, have a plan to fix them. Right? That means somewhere in your automations, you're throwing these. Sometimes they're unavoidable.

That's okay.

Use friendly error messages.

So as users, right, we're working with our teams. Right? We always want to say, hey, you rented that thing. Send us a screenshot.

They never send a screenshot. We remind them every single time. Right? Hey, where were you?

Please detail out these things. These are things that we request from our users, but those are just favors. Right? Like, there's other tools we can use to make sure that we always get the information that we want.

My favorite is breadcrumbs.

All of my error messages have the name of the automation in some way and the exact error code that it is. It doesn't mean anything to the user. Right? If I'm looking at this and I see a c c v r zero zero one as a user, I don't know what that is. Even as a developer, I don't know what that is. But I have a spreadsheet that lists all these errors so I can instantly know where and what automation and why it failed.

You see these all the time. Right? Even in Salesforce, you get that, you know, nice failure error code. That actually does mean something most of the time. So you use these as a pointer to tell you where things are.

And by the way, task failed successfully.

Not a good error message, but it does make for good humor.

So we see these in our flows. If we don't have any sort of error handling, we run into an issue, we get this message.

If you're the user, what are you thinking right now? You're like, crap.

This sucks. I'm trying to get my job done. Now I have to go hunt down an admin. What's going on? Is this on me? Is that on them?

So we can take it one step further and start to customize these errors.

This is good. Not great.

This is the default flow error message. Right? So if I have a fault error handler, this is what it's going to spit out most of the time. Unlike this one, which is your unhandled error email, the exact same thing we saw on the prior screen.

But this doesn't tell the user or anything. Cool. There's a pick list. It has some bad values in it.

Which pick list? How do I fix that? What should I use? Is this my issue, or is this Matt's issue?

So we can go one step further.

When updating this account using this flow, there was an issue.

Check that you used a valid pick list for this exact pick list, and then try again.

If you still experience this error, go to this channel, and here's where you can get help. Reference this error message. If you're super awesome later on, we're going to show you another way where this call automatically gets logged for you, and you already know that an error happened way ahead of time and can start to look into it.

Is this the best error email? No. This is something I did in, like, five minutes. I'm also an engineer. We're really bad at text. But you can work with your BAs, right, or your design team, or even yourself to come up with better error messages. And you can customize it to yourself, but always let that user know exactly how they can, a, fix the solution, and then, b, get help.

So peanut butter and jelly. Peanut butter and chocolate. Anybody else know any other famous duos? Halls and Oates, Yankees versus Red Sox? No, that's a bad one. Anyone?

We're gonna go with fault paths. Every fault path, just like peanut butter and jelly, actually every DML operation needs a fault path. That was horrible. But why?

Right? So every single one of these is sometime that you're interacting with that database. This is where something bad could happen. If you're writing to the database, maybe you run into a validation error.

Maybe you run into a lock in row error. Maybe you just don't have access to that record.

If you're deleting it and something fails, right, now you're sending all of those unhandled error exceptions. You know, that user gets a bad exception.

If you have a multi tiered process and you were depending on step one completing before step two completes, you went ahead and borked things. Right? Or if you don't care about that step and your flow can con concede without running into those issues, you wanna let it handle itself. So fault paths. If you don't take anything else from this, presentation, every time you have one of those pink boxes, you need one of these. Right?

How you handle those errors are all about you and your business. I personally recommend Nebula Logger.

If you want to learn more of that, in about an hour, you can actually learn more about that from the creator of Nebula Logger right here on this stage. Highly recommend it. It will unlock a lot of your issues.

The reason is, anytime I have one of those error messages now, I'm logging that in and I can see that. I now have a dashboard. I might have a Slack alert for any critical, you know, rev ops functions that I need to solve immediately. I don't have to wait for that user to post. I don't have to wait for that user to get so frustrated that they've done it fifteen different times and had a failure that they finally email me or they went to let their friends. Right? We know automatically ahead of time.

Entry criteria.

Another thing that we all need.

If you have seven or eight or nine or ten flows all in one object running at a time, all unrestricted, that means every time that that flow runs or that record runs, you have eight or nine or ten potential flows or Apex also executing every single time.

Use these entry criteria to keep your records from running multiple times, keep things streamlined, and also keep your records from updating the same time over and over because remember your flow executions.

This also improves your readability. If I know that this flow is only gonna fire under these circumstances, if I'm troubleshooting, I know exactly I can rule that one out versus if you have all these flows running unrestricted, it's the wild west.

Personally, I ran into an issue where I would have a flow that would update six different times. I couldn't figure it out. It would just every single time I updated it, it would run six times. I entered one piece of record criteria into it.

It only ran that one time. This gets worse if you have reverse ETL jobs that come into your org and they're just updating a field that you don't even care about. It's not even part of your process. Say it's like account live date.

That flow is gonna run every single time that reverse ETL job runs. And if you have a lot of data, you're potentially gonna run into locking errors. What do those locking errors prevent? Your reverse ETL job from actually updating that field that you need.

So please use record entry criteria. This is something we do on the Apex side, right? We have trigger frameworks. We say only run this if this piece happens.

It really keeps things streamlined.

So readability.

Sorry to disappoint you if you don't already know this. You're gonna spend more time reading flows than you're ever gonna spend writing them. Why? You're gonna come back behind it. Right? What did somebody write for you? What did you write, personally?

You know, you need to be able to make things make sense to you. So how many of you have written up awesome automation? You're just like, yeah, this is gonna change the world. Then the user comes back and like, cool, we wanna tweak it. It's been maybe six months. And you go like this.

You have no idea what you wrote six months ago. You have no idea where to start. You know it's flow. You know it makes sense because you did it right and you would never make mistakes. But you have no idea how you did it.

So we need to remember what we're thinking, right?

I can't tell you this first tip right here. Don't be clever. Like there are so many ways to just do crazy, cool looking things, right? One liners in the code world or on Flow. Don't be clever, right? You're gonna outsmart yourself in the future. You're gonna outsmart everyone else.

Simple is good. Right? It doesn't make you feel like it's cool in leak code, if you are into that, but it gets the job done.

Use naming conventions. I don't care which naming conventions you use, just stick with one. If you're gonna use camel case for naming variables, save camel case. If you're Gonna use snake case for, naming variables, stick to case snake case. Salesforce product managers, if you can keep that consistent in flow when you make elements, that would be great. But have a naming convention.

Make sure that if you're gonna say a variable starts with v a r, that's cool. A formula starts with f m.

Whatever you need, Make variables and steps easy to read.

What is that variable?

Opportunity date. Right?

You know, if you're creating an opportunity, don't say just create record. Say create an opportunity for, you know, an amendment. Whatever it makes so that you can go back and read it.

And then comments and descriptions. You don't have to put a description on every element, Right? If it makes sense logically, leave it. But if you made some assumptions there or it's not something that makes sense, please add it in the description field.

It helps everyone else out. And then if you have a very complex formula, say it's, you know, twenty lines, break those into smaller formulas and smaller bits and pieces so you can go back and figure out what does that mean. And you can also troubleshoot each individual component to make sure that, you know, it's not your whole logic. It might just be one piece.

So observability.

It's a hardware to say after lunch on stage. But it's know your org. Right? This is a big concept we have in traditional software engineering. These are the tools like Datadog out there, Century, all these alerting platforms where we can tail logs and know exactly what occurred.

This is where there's dragons, right? So you wanna know where your org is. That flow that I had that executed six times, if I didn't have any logging, I wouldn't know, right? I would just know that it takes thirty seconds to save an opportunity, which is way too long.

But I can insert log components and tied to something like Nebula Logger. Right? Where I can sit here and go debug. I only wanna run this when I'm actually trying to test something and figure it out.

Info. I'm a huge fan of info. Every flow and every Apex trigger, every single code I have, I have a flow start and a flow end. How do I why do I put that?

You know, it's an extra time, it's extra run time, right? It's all that. But I know for a fact that this automation started and this automation ended. Even if it failed, I know that it actually did end.

An error. Right? Warn. Warn's also a great one. You don't wanna interrupt the flow of the user.

You don't want to alert them that something bad happened. But you yourself wanna know, hey, this flow did something that we didn't expect. It didn't actually break anything, but we need to go look into it. Maybe we have a decision element that went down the wrong way.

Maybe we had an entry criteria that wasn't too specific.

So what can you do with these logs? Log when that flow starts. Log when it ends. How long it takes, right? Is it taking thirty seconds on average? That's probably way too long. Drop that down to two.

But my favorite is alert when something doesn't happen.

How many of you have that job that runs once a day, twice a day, three times a day, that it's super critical, and the next morning you wake up and you get that knock from finance, right? And like, hey, our sync job didn't run. Is something broken?

If you have that logged, you automatically know and can alert and then even have retries to go, cool, run that job again. It did not run. Let's figure out why. You don't have to wait until finance or, you know, rev ops comes knocking on your door. You already know, and you can have an answer for them before they even come. And you can be proactive, which always makes you look great.

When you have observability, this is a Datadog dashboard. It's one of my favorite tools to use. If your company has it, try to get access to it because you can send those logs and you can look at more things. If you're a shield, or event monitoring user, you have this out of the box.

You can connect it to Datadog as part of it, and that lets you know the health of your org, what your automations are running, how long is it taking, do you have error logs, even user logins. But I come in here and I look and say, cool. Here's the health of this particular sync that I have running. I know right way, looking at this, it's all green.

I don't have to look you know, worry about anything. If I come in the next day and I'm like, this is down to two hundred thousand, that's an anomaly, and I have an issue.

When you leverage something like Datadog as well, speaking of AI, right, if you're pumping these things in, they have their own AI and anomaly detection. So it can do these things for you and figure out what the health is. Modularity.

Be dry. Dry is a great thing. What is dry? Don't repeat yourself.

This is a huge thing when we write Apex. Right? We take modules and classes and compose them down into individual components that we can reuse.

Coming from a software engineering side, right, any function or method should only have one purpose.

So should your flow. Right? That's harder to do in flows because of the way they're composed. But really, when I pull one flow open, I should say this is its job.

It shouldn't be doing this if this happens, this if this happens, this if this happens, and then five hundred things under here. Because then you can't use entry criteria effectively. Right? If something breaks and you divert down a different path, you don't know if you should have.

So use sub flows. Right? Those small components that you can keep on going.

Me personally, my error handlers are all subpaths. When I go in, I know I only have to edit that one subflow versus going into every single flow to update it. It also helps with troubleshooting. Right?

How many times do you go in and you're like, hey, this thing's broken. Or if I fix this, what else is gonna break? With that subflow, you instantly know all of your logic is self contained within that one.

Creating a common error handler and assign to areas of responsibility. This is gonna be huge, this last piece, if automation center is going to be doing what it's doing in the future with marketing. You can actually create those areas of responsibilities on a subflow that you only want your engineers to handle or maybe your super admins for callouts.

And then delegate the rest of that to another flow. So you know this flow is protected. Maybe it's interacting with your ERP and you don't want an average, admin or marketer to update that flow. You can contain it. That way, you keep that operation excellence around it.

Test and test some more.

Any change that you make to a flow or Apex may cause a regression.

No one likes fixing those bugs. So stop it before they happen. And that's by having a test plan.

Shortly after this, there's gonna be a great session on UAT. I highly recommend going into it. But UAT doesn't mean that user. It also means yourself.

Right? You're that user. Go in and have those test scripts. If you're doing manual things, develop them.

Manual test scripts are great. Those are the ones where you say, hey, create a record, do this, check this, expect it to happen. What happens though? Right?

We're all busy. We all get tired. We don't like to do monotonous tasks. People skip it.

People will just assume that's a small change and they go with it. We're all humans. It happens. But especially if it's a revenue operating, you know, unpacking one, I highly recommend having those manual test scripts and written out.

And then tweak them as you tweak your flow is the important piece. And then automated testing.

Let me be careful here.

There is no automated testing for Flow as it stands today.

So your best bet is probably a commercial or your own developed internal flow or test, probably an Apex. It kind of defeats the purpose of flow. But there is a great vendor here today that you can talk to out in the vendor booth who does a lot of automation testing that you can go around.

And then augment flows with test.

The reason I harp on test, right, is as you go those goes through them, you can say and write, hey, when I create this record, I'm gonna assert that these five things happen. If these five things happen, I know that my flow did not introduce any regressions. If it throws an error, I have something to look at.

Downside to testing with Salesforce and when it comes to low code, the flow tests that exist today require record to be created. If you're using a CICD pipeline, that record doesn't exist in all of your environments.

They're limited to only two hundred records to be created within a test.

You can't run a test suite, so you can't say I'm deploying this flow, run all the tests around it.

And then you can, of course, edit those flows directly in production, which violates all of your testing anyway because those test suites won't run.

And finally, my big thing. Use lower environments.

Lower environments don't mean sad environments, so they're down for the day. They just mean not prod.

Always do your testing in prod because you shouldn't develop in prod. Don't.

As an Apex developer, I can't, never have been able to. For some reason, Salesforce, way back when, said, hey, Matt. You're really smart, but you're too smart. We're not gonna trust you to do things in prod. Here's ways to test it over here. It protects the platform, right? Maybe I just a crazy race condition that took down my server and all my friends next to it, and now I have a whole bunch of angry friends.

One easy fix can damage millions of records.

Today, it's even worse because now you have callouts.

So one easy fix that you think, hey, cool. I know exactly that issue. Boom. I'm gonna hit it and save it.

Not only can bork your org, it can bork your ERP. It can bork your order management system. It can bork your financials, compliance regulation. It can delete records out of other platforms.

So please, even though it's only easy fix, test it in a lower environment first.

Test before prod.

Just because you did it in a lower environment doesn't mean it's safe. Still gotta test it, right? Because that one easy fix, you could have had a horrible assumption that went wrong.

And finally, just don't develop and prod.

I know there's a lot of orgs out there, right, where you have a lot of red tape or maybe you're a solo admin and you just have a lot going on.

But it takes five seconds to, if you have CLI, to pull something from your sandbox and push it to sandbox. Literally five seconds. I mean, I could write that line for you today, five seconds. It doesn't take that much time.

You don't have to do change sets. If you have something like GearSet, Orcapado, or even your own whole, you know, hand rolled CICD pipeline, please use it. It doesn't take that much time to do something in a lower environment and push it up. Now I know there's limitations.

Right? You might not have that data in your lower org. You might need some data seeding. Those are all, you know, certain issues that we have, but I can't can't overemphasize this.

There's been so many times in my personal experience as a junior engineer where I thought I knew something and I didn't. Right? It was like I completely it was humble pie. So please just protect yourself and your orgs.

Use lower environments and test. So thank you. I have time for questions. If you like this series, every Thursday I post something for Flow like a developer.

If you have any ideas, that's great. I plan on presenting this again, so if you have any feedback, I'll take it. But what questions do you have?

None, because I'm awesome. Yes? How many flows on an object would be too many? How many flows on an object would be too many?

It depends. Right? So entry criteria, if you have those narrowed down, it's perfect. Right? Like, have as many as you want.

If they're self contained, you're good as well. So there's really no hard and set answer. It's really just that performance. And then have you modularized yourself or you repeated yourself across those?

Does that help answer your question? Yes. Thanks. Yeah.

Next.

How do you approach, optimizing or, you know, improving that situation? So the question was, there was guidance. Right? You should only have one trigger or one record triggered flow on on any given object.

At Chuckle, right, that's a practice no one's gonna follow. It's impossible, right? You've either inherited Apex or you need Apex that runs something or you have Flow. That's a maintenance nightmare. Add on to that all of your managed packages which inherently have triggers. It's just not a feasible thing.

What I will say though is know which triggers are firing and when and know when your flows are firing and when. And then make sure that they don't duplicate or they step on each other. I've seen a lot of triggers, especially with order of execution, that will fire before another flow. And that flow will then update that trigger and then fire that trigger again and over and over and over.

So know your order of execution. Right? So, there used to be a bigger diagram. Now with workflow rules and all that out of practice, it's simpler.

But yeah, that's my advice is just know which automation they're firing them in.

We have an Apex class. Does it make sense to instead of writing, like, a trigger framework, you just go use a flow to trigger the Apex?

Yeah. So the question is and this is a good one, I like this. So the idea here is if you have a trigger framework, and if you don't know what a trigger framework it is, right, it says, hey, fire this trigger when in this order.

The question was, if you have those classes in Apex, would it make sense to put those into a flow and let the flow fire them as invokeable action?

I think you could get away with that, but the question is, what's your performance hit, right? Because you have to spin up that flow and you have to spin up that apex. Invocable actions also have, restrictions on what you can pass into them and when. So you would be kind of bottlenecking yourself to a point there.

But I have seen quite a few flows where they do fire an invoke action, on a record trigger flow versus a trigger just because it's faster for them and they can see it in that admin side, right? Like ninety percent of their org is flows and they have like ten percent of Apex, so it makes sense for them. But I don't think yet. Especially because you can't call Apex from before safe flows.

But you can call Apex on before safe triggers.

Didn't know if you knew that.

Cool. Yeah.

One thing I've missed a lot coming from a development background in flow is the lack of any widely adopted style guide naming conventions outside of an individual org. Are you aware of any efforts to do that more broadly?

There is no official linter.

However, I can't remember the name, and Nicholas is going to yell at me after this.

There is a Versus code extension you can get that does linter flows and analyzes them for best practices. So it's a lot like PMD. It's not as robust yet, but it's getting there. And so for those who don't know what a linter is in the software engineering side, if I write a bunch of code and I just don't indent it, write, you know, have some bad name and conventions, all of that, the linter will read it and say, yeah, fix this, right, or indent here or use this naming convention or you call things in there.

You mean Megalinter? Megalinter is a linter, but it's not the only linter. Yeah. Yeah.

Four for Salesforce, yeah. That's probably the best accepted one.

Any other questions? Hi.

What do you suggest to someone who is trying to convert or merge around two hundred workflows to a flow. Is there any particular tool, or is there should be some kind of a strategy you suggest?

So let me make sure I answer the question. So coming new to Flow, like, how do you get started and and kind of get the best practice?

So now process builders and workflows are going to be obsolete.

Yep.

So we are trying to merge or convert the existing workflows and the process builder to the flow, but they are too many. Yep.

Yeah. So from that side, I would say start with what are your most impactful and what are your most big ones that impact a lot of your business. Right? Like, and which ones are you gonna edit the most? And then start from there and build on.

The one strategy I would say is Salesforce has released an awesome tool, which is the process builder to flow converter.

Don't automatically accept it. No. Definitely.

But definitely. It will literally do what you wanted it to do from process builder, but it doesn't actually pull in any of the best practices. So use that as a stepping guide, see what it would do, and then look at your other flows and figure out how you know, do you have any overlap? Can you combine them in subflows?

That's really the strategy, unfortunately. Like, to pull those out, I would say it's it's it's a replatforming and refactoring world. Right? Like, you really need to focus in on what's your critical.

Are these things actually working? Are they needed? I would strip the fat first. If nothing's needed, don't worry about it.

Right? You're not gonna need it. And then focus on your revenue impacting and and critical ones. And then from there, you can possibly let the other ones die.

But if anyone else has suggestions over here, if you've done it, help them out.

Thank you.

Thank you.

Yeah. I think I have time for one more. Okay.

Okay. Of how I mean, one of the scenarios where I, I'm not sure if you're gonna be able to get a things.

I mean, one of the scenarios where I my I mean, we did discovered is, we have plenty of workflows that can be merged into one flow, but we have to do it manually.

Yeah.

I did not find any kind of a tool or anything which can just merge those twenty, thirty workflows into one flow. So that's manual work.

If if it's fan if you're fancy, you could write the XML and copy pasta into it, but, yeah, that's another level of of advance.

Thank you. Cool. I'm out of time. There's another speaker coming here, but I know a lot of people don't like asking questions in public. I'll be over in that corner for anyone, who just wants to connect. But thank you so much for your time.