Aaron Stannard on Technical Debt and Optionality

I’ve written about technical debt before, (and will probably write about it a million times before all the writing is done), but the reason we’re chatting today, or rather, the reason you’re staring at these words on your computer monitor (how quaint), is that Aaron Stannard has written about technical debt too and he adds a dimension I hadn’t considered previously: optionality (if you’re into investing, this is similar to stock options or options trading).

I think this is a thoughtful and useful take; and it’s worth your time.

You can also find Aaron Stannard on twitter.

[Last Week in .NET #59] – Min/Max Life Changes

Saturday marked the 20th anniversary of the September 11, 2001 attacks; the effects of which changed the lives of billions of people. In a “very significant to me” moment but “incredibly insignificant to the world” view, I would never have met my wife or have the life and kids I have today if it weren’t for September 11th. A terrible event and aftermath that shaped reality as we know it. But this is not reminisce with George Stocker, it’s Last Week in .NET, so let’s get to it.

๐Ÿ‘€Minimal APIs at a glance in .NET 6 Scott Hanselman digs into what minimal APIs are and how they work. ‘Minimally’ is apparently the right answer.

๐ŸงDavid Fowler tweets a thread explaining the coolness behind Minimal APIs, and I’ve said it before and I’ll say it again. This is why I’m on twitter. This sort of thing would have been too minor to make a whole blog post out of, but is perfect for twitter.

๐ŸŽฉAmazon, Google, Microsoft, Cobra Command, and other tech companies are in a ‘frenzy’ to help ICE build its own data-mining tool for targeting unauthorized workers “Don’t be Evil” has a second part that isn’t usually vocalized: “unless we can make money being evil.”

๐ŸˆMatrix Resurrections: Official Trailer #1 is out 1999 called, and the Low rise jeans are coming back as well. This trailer made me very happy, and I hope the 4th iteration of the Matrix captures the magic the first one held.

โž–An Opinionated Look at Minimal API in .NET 6 a look at one of the possible ways to put minimal APIs into action. This is a first blush attempt, and while it may not be the solution, it at least gets us asking the right questions.

๐Ÿ’ฉGithub (2008) Merges ‘useless garbage’ says Linux Torvalds as new NTFS (1993) support added to Linux (1991) kernel 5.15 The creator of Git(2005) says that Github creates useless merges, while conversing on a listserve (1986) and accepting merge requests through Email (1971) .patch files. Does Linux surf the World Wide Web (1991)? I have to wonder.

As promised last week, this week was a light week. I’ll see you all next week.

[Last Week in .NET #58] – Deep Learning Means Never Having to Say You’re Sorry

๐Ÿ‘ทโ€โ™€๏ธ Working with Nuget Local Packages An up to date look at how to publish nuget packages locally.

๐Ÿค–๐Ÿง  Plan for Deep Learning in .NET The Machine Learning team at Micorosoft has published their plan for Deep Learning in .NET; and in case you don’t know the difference between Deep Learning and Machine Learning, I looked it up and the difference is ‘fuckall’. In all seriousness it looks like the difference is that the Deep Learning folks want AI to make its own decisions, instead of using human provided data to make decisions.

โฌ‡Download New Azure Architecture Icons now! These icons look rather spiffy but you know some executive at Microsoft wanted the name ‘Azure’ somewhere on these icons.

1๏ธโƒฃ1๏ธโƒฃMicrosoft announces Windows 11 will release on October 5 for new and existing PCs, and in other news they’ve added about 10 CPUs from the 7XXX series Intel CPUs, AKA “Intel 7th-generation Core” chips. If there wasn’t a pandemic and a world-wide shortage of chips, I wouldn’t be so ticked at Microsoft for requiring a CPU from 2018 or later.

๐Ÿ˜ท TechBash 2021 has been postponed If you want some semblance of normal: Get vaccinated if you can. Otherwise we’re likely to hear this same tune in 2022 as well.

2๏ธโƒฃ2๏ธโƒฃThere’s a Microsoft Event on September 22nd at 11am ET. I’ll be live tweeting this (@gortok on twitter).

๐Ÿšจ US CYBERCOM releases a cybersecurity alert about Atlassian Confluence CVE-2021-26084 and this CVE is bad enough for the US Fricking Government to use twitter to provide immediately and timely advice. If you use Atlassian Confluence on-prem, you want to patch immediately.

All in all a pretty light week; and with the short week this week it’s expected that next week will also be pretty light.

[Last Week in .NET #57] – So, Azure your keys are safe?

The biggest news this week (and will likely trump any sort of news for the next couple of weeks in the Microsoft space) is that Azure has a vulnerability dubbed “ChaosDB” that exposed its customers keys to the world, leaving every single CosmosDB customer’s database data exposed for the taking. There’s a technical deep-dive into this vulnerability as well. I hope the Azure team is wearing their brown pants.

This is as bad as it gets. Good news though! They gave out a bounty of $40,000 to the finder of this vulnerability. Which values this vulnerability as akin to a Tesla Model 3 — and not even a fully decked out one.

โญ• Apply rounded corners in desktop apps for Windows 11. In some cases, rounded corners will be applied to your applications automatically, in others, here’s what you can do to make them rounded. As Apple intended.

๐Ÿ› Razer Bug lets you become a Windows 10 admin by plugging in a mouse. This is a pretty easy exploit to… well.. exploit, so if you’re using Razer mouses in a corporate context, you may want to rethink that decision.

๐Ÿคทโ€โ™‚๏ธ The real names of features in Visual Studio. It’s a bit inside baseball, but still a wonderful walkthrough.

๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง David Fowler writes to tell us that New .NET 6 APIS [are] driven by the developer community. In this blog post, David details new APIs available in .NET 6, and highlights the fact that well, they were authored by members of the community. I’m a fan of Parallel.ForEachAsync, as that seems rather useful for my needs.

๐Ÿƒโ€โ™€๏ธ This is your warning: Get out of the Dev Channel for Windows 11 unless you want to experience some turbelance. If you want stability, use the beta channel or get out of the insider program entirely. If you want to see new builds of Windows 11 that may have the stability of Windows Vista, stay in the Dev channel.

๐Ÿ™Œ Nicole Miller-Abuhakmeh is the new Community Manager for the .NET Foundation. This is a wonderful choice for CM, congrats Nicole and the .NET foundation.

๐Ÿ™€ Looks like there’s another tactic available to exploit Proxyshell vulnerabilities. A few weeks ago, a researcher showed off an exploit of Microsoft Exchange Server dubbed ‘ProxyShell’ and it seems like the gift that keeps on giving to attackers. Bottom line: keep your Exchange servers up to date.

๐ŸŽฒ In .NET 6, FirstOrDefault(), LastOrDefault() and SingleOrDefault() now let’s you specify a default value. Sadly it has to be a compile-time constant so you can’t have something like new Random().Next() available.

๐Ÿ—“ Microsoft Ignite is November 2-4, 2021 and is virtual again this year because people can’t bother to vaccinate.

โœˆ Github’s Copilot can get you in trouble 40% of the time and if you’re the type to use AI to write code, maybe you deserve to have problems.

๐Ÿถ Using SignalR in your Blazor applications This is an nice pairing of technologies. Like Chardonnay and Brie, or Hotdog and Chili. Ketchup is forbidden, Mustard is recommended, however.

And I say this with a twing of irony, but that’s it for what happened Last Week in .NET.

[Last Week in .NET #56] – Silverlighted Sorting

No releases this week; but lots of interesting tidbits nonetheless. If you read just one article this week, check out “The Myth of the Treasure Fox”. Link below, of course.

๐Ÿ’ง Get the Drop on Sorting. Kevlin Henney does a deep dive on the drop-sort, a sorting algorithm that sorts by dropping elements in the collection. This is not as useless as it immediately appears, and Kevlin explains why. It’s engaging and informative.

๐Ÿฅ‰ In a screenshot that is strangely alluring Maarten shows off what VB looks like in the brave new world of .NET 6, with a pattern based XML Literal. If I were to rate VB on this screenshot alone, I’d give it a 12/10. Having worked in VB, I give it a 4/10. It’s slightly ahead of the readability of JavaScript 5, and slightly behind Python. These ratings are final.

๐ŸŒŸ๐Ÿคบ Chat Wars! How microsoft tried (and failed) to keep MSN compatibility with AIM. If AIM and MSN were still alive, they’d have graduated college by now and be grumbling about the state of the job market. I mean, they unemployed, strictly speaking, with AIM having been retired in 2017, and MSN Messenger having been retired in 2014.

๐Ÿ”‘ .NET 5 Support of Azure Functions OpenAPI Extension Yes, now Azure Functions support .NET 5 for OpenAPI Extensions. If you, like me, have no idea what that is, then this blog post isn’t for you! (It’s becoming increasingly clear that these blog-posts with keyword laden titles are there to help hit some sort of internal Microsoft KPI related to pushing Azure). “George, you’re being unfair!”, I can hear you say. If I’m being unfair, then why aren’t these blog post titles telling you the outcomes they can help you acheive, instead of keywords of processes related to their own products?

๐Ÿ”ฎ No, NVidia Didn’t Fool Everyone with a Computer-Generated CEO In case you missed this, NVidia used a Computer Generated capture of its CEO for a short scene in its presentation, but their initial blog post on the subject made it seem like they used the CG’d CEO throughout. It’s still impressive, bu tnot nearly as impressive as initially made out to be.

๐Ÿ†• Microsoft revamps Visual Studio JavaScript projects in forthcoming version. Visual Studio will now rely on whatever the ‘system’ has installed for JavaScript frameworks when creating a new JavaScript-ish project in Visual Studio 2022. I assume it will work seamlessly with things like nodeenv and other virtual environments, and if it doesn’t that would be a bit embarassing, wouldn’t it?

โœ… .NET Optional SDK Workloads This came about because I saw the word ‘workload’ in reference to .NET, and had no idea what it meant. It means a way to extend the SDK to do other things than it’s meant to. I can’t figure out if this is a public thing (you too can write extensions for the SDK) or if this is a Microsoft Only addition, or who this is even for.

โ˜  A Decade Later, .NET Developers Still Fear being ‘Silverlighted’ by Microsoft. Killing Silverlight was the closest thing .NET Developers had to experiencing the Red Wedding. An entire developer stack killed overnight. I don’t claim there’s any sort of ‘guest right’ when it comes to Technology Stacks, but there’s a certain amount of creative destruction taking place that Microsoft was not known for previously. They have several hundred projects to kill to even get close to Google’s bloodthirstiness. There are, of course, differing views, as is the norm on Twitter.

โœˆ Async code has signficantly less overhead using .NET 5 compared to .NET Core 3.1. Screenshots of the benchmarks in the link if you like that sort of thing.

๐ŸฆŠ The myth of the treasure fox in Skyrim. This is why I love twitter. You learn things you’d otherwise never hear about. I won’t spoil the story for you, but it’s worth your time to read.

๐Ÿ’ผ Introducing DevOps-Friendly EF Core Migration Bundles. DevOps here means “Deploying your code easily” and has nothing to do with Azure DevOps (either Azure DevOps On-Prem, or Azure DevOps on Azure — and no, I’m never letting Microsoft live that atrocious naming down). Anyway, The EF Core team has made it easier to run database migrations in a CI environment.

๐ŸŸก Highlights from Git 2.33. The news here is that git now has a new rewritten and faster merge strategy called merge-ort. To try it out (it’s not the default yet), you can use the command git merge -s ort when merging two branches in git. The -s ort is some sort of a cruel joke, I think. Or at least proof that no one talks their way through commands any more. Can you imagine telling someone with your mouth-words how to do it? “Type g i t space dash s space o r t”.

๐Ÿš„Performance Improvements in .NET 6. If you like performance blog posts and you tolerate IL, this blog post is for you. As deep a dive as you’ll get on just what performance improvements have been made in .NET 6, and what it looks like under the covers.

โฉVisual Studio 2022 Preview 3 offers a new breakpoint context menu to set advanced breakpoints more easily. If you don’t use advanced breakpoints, they’re quite magical to improving productivity when debugging — like setting a breakpoint after a specific number of times, or setting conditional breakpoints.

๐Ÿ‘ŽIn the “We can’t help being evil” department, It’s harder to switch default browsers in Windows 11. Besides the tweet, there’s an in-depth article about it on the verge, and what that means for us. Since 90s clothing is come back in style, I suppose 90s monopoly practices should too?

๐Ÿ™ƒ You can now have global using static <class>.. This is a great idea. I mean, globals are already a time-honored programmer tradition, and of course seeing methods being called that you have to have an IDE to trace is a wonderful idea.

And that’s it for what happened last week in .NET. It was a light week; but as we get closer to November (and .NET 6), we should see more releases.

Houses, Forcing Functions, and Containers

In my last post, I talked about microservices compared to houses. A giant house with lots of stuff in it is hard to find anything. A small house with lots of stuff in it is hard to find anything. A small house with the right amount of stuff in that house makes it easy to find that stuff. In fact, labeling and putting everything in its place helps even more.

Jimmy Bosse wrote:

I think the nooks and crannies are a natural result of years of maintenance and the rotation of team members. Each class is essentially the most micro of services. Moving to a micro service feels like itโ€™s neater just like moving to a new home is neater. Youโ€™ve just gone through all the crap and cleaned house in order to move. Over time those micro services will build their own books and crannies as features built under deadlines pile on team members move on to greener pastures. Entropy is coming for everything. No architecture can stop it.

Jimmy Bosse, “A house small enough to fit everything in”

I love this comment because who among us hasn’t had this happen multiple times? It’s almost a rite of passage to have your system live long enough to become the villain and there to be people that want to move to a new system. How many times have you or someone you’ve worked with advocated a rewrite with that same thought in mind?

That’s what we’re trying to stop, right? No one in the business ever wants the code rewritten, and the longer you spend in this industry the more you realize a rewrite is in the same vein as a self-licking ice cream cone: it sounds nice but when you think about it is on some level absurd and another level impossible. (Why do we rewrite software? So we can avoid rewriting software!)

That’s why I think event-driven architecture especially and services-oriented architecture (SOA) and microservices topologies in particular have a leg up on our past efforts. Our problem previously was there was no size constraint: all boundaries were soft boundaries. Since everything was deployed together in a monolith, eventually you’d end up with a big blob of software. With SOA, you now had to name those blobs and make a hard separation point at a network boundary, and of course there was more than one of them. This was better because of course we’d rather fight 10 chicken sized horses, than fight one horse-sized chicken. And then we got microservices and now we have 100 chicken-sized horses and we realized that was enough slices.

So there has to be a balance: You can’t just divvy items up and put them in containers and expect everyone to find what they’re looking for — especially if at some point you start naming that container “utility”, you have to actually spend time naming and planning, in any case. But at least with event-driven architecture you get two things you didn’t have previously: No one can reach into someone else’s box, and the network boundary is well-defined.

The bottom line is that entropy comes for us all; Jimmy’s right about that. We’ve tried soft boundaries, and they didn’t work. We tried hard boundaries and they seem to work a little better; but that coupling is a problem. With Event Driven architecture we can truly finally have a loosely coupled system enforced more easily than the soft boundaries we had before.

P.S. I got what appears to be a concussion over my vacation and so there’s a lot of weird association (and fogginess) going on in my mind right now. I’m going to proof-read this in the morning before I hit post; but if it’s too out there, don’t hold it too much against me.

[Last Week in .NET #55] – Squabbling Trillionaires.

Releases

๐Ÿ”ฎ Magick.NET 8.2.0 has been released which is an image manipulation library for .NET.

๐Ÿ“ข Windows App SDK 1.0.0-experimental has been releasedand Kevin Gallo attended the App Development Community STandup to underscore why it’s an important release. The release notes tout several experimental features, push notifications and windowing improvements.

๐Ÿ“ข Visual Studio 2022 Preview 3 now available! This preview release includes improvements to the Dark Theme, added new JavaScript and TypeScript project types, and because of course they did, easier one click publishing to Azure DevOps.

๐Ÿ“ข Announcing .NET 6 Preview 7. There’s new .NET SDK templates that use the latest C# features and now there’s literally a one line console application template. Everyone wants to be like Perl.

๐Ÿ“ข .NET 5.0.9 has been released. There are several CVEs resolved in this release, including CVE-2021-34485, an information disclosure vulnerability related to crash dumps, CVE-2021-26423, a Denial of Service Vulnerability, and CVE-2021-34532 which is an ASP.ENT Core Information Disclosure Vulnerability, this time areound logging JWT tokens that are unparsable.

๐Ÿ“ข .NET Core 3.1.18 has been released and these same vulnerability were backported from .NET 5 to this release.

๐Ÿ™Œ Github Codespaces has been released and you can access it from any repository by pressing the period key. Yes, launch a Visual Studio Code instance, in your browser, already targetting a repository with a single keypress. That’s pretty remarkable and allows me to forgive the many sins JavaScript committed.

News and Notes

๐Ÿ™‹โ€โ™‚๏ธ Microsoft abandons semi-annual releases for Windows Server. Opting instead for the ‘You can have frequent updates if you want to use Azure’ which already fills this week’s bingo for requiring Azure needlessly because it’s on someone’s KPI. Joking aside, this is a dive into marrying frequent Windows Server updates with using Azure HCI (Hyper Converged Infrastructure), and it appears that Windows Container updates will now be married to that same infrastructure. Just as well, I suppose since outside of Azure, Windows containers are as rare as an honest politician.

โ“ Microsoft deprecated the Snipping Tool, and asked everyone top move to Snip/Sketch and now they renamed Snip/Sketch to Snipping tool, and we’ve once again been reminded that naming is hard for Microsoft.

๐Ÿ“น Aaron Stannard is hosting a webinar called “Introduction to Akka.NET Streams” on August 27th. If you’re interested but your dance card is full on the 27th, you can register and watch later.

๐Ÿ—ฃ .NET Conf is November 9th-11th, 2021 and the CFPs are open. As usual I’ll be live-tweeting the interesting bits of the conference.

๐ŸŽ‰ Jetbrains is celebrating the release of 2021.2 of Resharper and Rider with a … party? This ‘party’ is being livestreamed on August 17th, 2021 at 10:00 EDT (-4 UTC).

โ€ผ One of the more interesting bits of Visual Studio 2022 going 64-bit is that ReSharper can now use more memory. Previously it shared the max 4GB of memory with VIsual Studio. Will performance improve? We’re given a vague “it depends”, which is… fitting.

๐Ÿคทโ€โ™€๏ธ Windows 11 FAQ: Here’s everything you need to know says ZDNet. If you’re looking to upgrade, here’s what you need to know: Buy a computer with a new processor.

๐Ÿฅ” CodeMash 2022 CFP is open, and closes August 31st, 2021. I haven’t been to Codemash myself, but I’d love to attend.

๐Ÿฆท .NET Core 2.1 is end of life at the end of August. It’s getting pretty long in the tooth so migrate now.

๐Ÿฅˆ๐Ÿ’ก Getting off Microsoft Silverlight for Good Silverlight goes out of support in 57 days, and Mobilize.NET, a consultancy that helps companies migrate off of it want you to know this.

๐Ÿฅ‡ For the F# Folks, Don Syme, one of the language team members for F#, talks about active pattern matching in F# and why it’s superior to alternative forms of matching. I mean you wouldn’t expect an F# person to ever say it isn’t superior, would you?

and lastly, and because I’m obligated to report it but not because I care:

๐Ÿค‘ Microsoft and Amazon battle over yet another $10 billion U.S. government cloud contract. Last time Amazon protested Microsoft winning a DoD Contract worth $10 Billion, and now the shoe, as they say, is on the other foot. However, this time it’s the NSA, and I can’t find the words to care about the plight of the trillion dollar companies.

A house small enough to find everything in

I know of many times where a monolith feels like a giant house with lots of unknown nooks and crannies and hidden places.

Every time I open Visual Studio I feel like Iโ€™m going to find a new room or cabinet I didnโ€™t expect. Like the time when an old ASP.NET Webforms project used the Request[โ€œโ€] bag instead of using Request.Form, Request.QueryString, or Request.Cookies. In case this sounds normal to you, a malicious user can basically send one something via QueryString when you arenโ€™t expecting it and since thereโ€™s a fall through priority, it is an attack vector.

Thatโ€™s not even one line of code and yet it has implications for thousands of lines of code.

In the same vein, we are leaving from vacation today at a rental house to return to the real world and one of the techniques we use to pack up is to make everything visible. If it belongs to us, it goes in the middle of the floor. If it belongs to the rental property it gets put away. By making visible what needs to be packed or thrown away or recycled, we know how much work we have. To put it in tech terms, Weโ€™ve reduced the possible surface we need to handle to literally one space in an entire house.

itโ€™s hard to do that in a monolith. There are so many places a change can hide that itโ€™s impossible to find them all. Every day is literally a new surprise.

Good architectural techniques can and do help; but if you could, would you rather remove all the places change could hide, or would you treat the codebase as a house you have to sift through to find a change?

Thatโ€™s one reason why Microservices are so attractive. Imagine a space small enough you could see all corners of it at once, and know what youโ€™re looking for has to be there.

Thatโ€™s a good reason all by itself to want to move to Microservices.

How many Browser tabs do you have open?

Right now I have only one browser window open, but I have 21 tabs open (including the one where I’m writing this).

I couldn’t tell you what’s in those 20 other tabs right now if I tried; and they’re all recent tabs.

If we can have 21 tabs open but can’t remember what’s open in each, why do we expect our codebase to be any different?

That’s one of those little annoyances that Microservices can solve. You’re able to work on a problem and only have to worry about one tab; not twenty-one.

If you’re just spreading the information in one tab across 21, it’s not going to solve anything. The goal is to make each microservice self-contained with what you need, so you never have to switch contexts to get work done.


Isn’t that worth it?

Support Layers in Microservices Topologies

โ€‹One thing I mention frequently in the daily emails is the fact that microservices require a lot more operational support and development support than a monolith does.

In a monolith, once you’ve got your CI/CD set up; it’s set up. Production-wise, you only have to worry about your application server and your database server (and any reverse proxy), and the most complex your architecture gets is when it includes a load balancer and a web farm.

All in all, not relatively complex at all.

Now, Microservices are not synonymous with containerization; but generally microservices end up being containerized for ease-of-deployment.  You can also containerize your monolith (which I generally recommend as a forcing function to make it seamless for new developers to get started in your system), and so containers aren’t just a microservices fad, though they work nicely with microservices.

If you think of microservices as self-contained applications that each need deployment, operational support, and scaffolding to make it easy to develop a new microservice, then you start to realize there are lots of repeated problems you have to solve when developing Microservices:

  1. How do we add new microservices in a uniform way so that we don’t have twelve different ways to do logging, or healthchecks, or monitoring, or authentication or authorization?
  2. How do we make scaffolding that makes it easy to have a generated container image for a new microservice that has all the business and industry specific stuff we need? For instance, if you work in the US government space, you’re going to hear two phrases a lot: “STIGged” and “FIPS-140 compliant”. Your industry may have its own terms, but it’s the non-functional part thatevery application needs to have that you’d rather bake in than worry about doing it each time.
  3. How do we make tooling that makes it easy to generate contracts when new microservices are made?
  4. How do we provision new hardware (when in a private data-center) or provision new instances (when in a public cloud setting)?

Susan Fowler talks about these four types of problems in her book โ€‹Production Ready Microservicesโ€‹โ€‹, which talks about the ways that you get a microservice from development to production in a sustainable and scalable manner.

Susan mentions four ‘support’ layers you have with Microservices that you don’t have in a monolith (or if you have them, they were already solved long ago and you don’t need to worry about it now).

Layer 4: Microservices
Layer 3: Application Platform
Layer 2: Communication
Layer 1: Hardware/Host*

*I’ve modified layer 1 to be Hardware/Host (because like it or not, a docker image is a host, and has its own patch cycle).

For a development organization, here’s the sort of things you typically need to worry about in those layers:

Layer 1: OS updates; OS library updates; the actual hardware (if in a private datacenter); Virtual Instances staying up to date; local Docker registry
Layer 2: Message contracts; event queue infrastructure; scaffolding for generated types; OpenAPI tooling; Thrift/gRPC tooling
Layer 3: (if in .NET): private nuget (package) registry maintenance and tooling; Keeping .NET up to date;ย  CI/CD for each microservice, development tooling; internal tooling to make development easier; (above scaffolding for generated types can also be in this layer); logging and monitoring for microservices;making the application systemd compatible
Layer 4: tools to generate microservice-specific configurations; SSL certificates for each service (if needed); environment files; and any tooling that we’d need to apply to a specific type of microservice.

If you have these four support layers in place; then a developer simply has to create a new microservice and go; this tooling takes care of the rest.  This can look like all of the scaffolding being generated for them by internal CLIs.

Sounds like a lot, doesn’t it?  It is. But whether you automate it or make your development team do it manually, it still all has to be done, and is a cost to adopting microservices.