Monday, December 9, 2019

Troubleshooting Search in SharePoint Online

coverOver the past years I’ve aggregated patterns and ways I use when troubleshooting why search results does not appear in the way you would expect. Some of it has appeared as blog posts, but for a while I’ve been thinking of putting it into a structured format.

Hence the book “Troubleshooting Search in SharePoint Online” was born. The book is a brain dump of my experience combined with help from others, and is means as a self-help book on investigating search issues before you go to the step of filing a support ticket. If you end up filing a support ticket, the process should be smoother as well as you should have aggregated good information on what you have tried so far :)

The focus is on why items appear or don’t appear, or are missing values etc., not why your KQL queries are not working as intended. Combined with my previous book on search queries, you should be armed with good tools to build and investigate search.

If you’re still using SharePoint on-premises, many of the concepts still apply, so it’s still a good read.

Where can you get the book? Head over to Amazon!

Wednesday, October 16, 2019

Breaking SharePoint search since 2013 – a lesson into unintentional consequences of messing with out of the box managed properties


I’ll start this post with a revised version of “Mikael’s managed property rule of three”, now called “Mikael’s managed property rule of four”:

  1. Never ever mess with the out of the box managed properties.
  2. Use automatic/implicit managed properties if possible.
  3. Map crawled properties (the plain ows_columnname ones) to the RefinableXXYY re-usable properties if possible. And do give them a unique alias for easier management and use.
  4. Create a custom managed property as last resort – which is only possible for Text and Yes/No columns.

Following these four rules will make your life easier, and help out troubleshooting search issues you might encounter.

Sometimes you think you know it all and then SharePoint search throws you a curveball. It’s been dormant all these years as it’s pretty much an edge case, but knowing this trick you can effectively break SharePoint search experiences quite magnificently :) Sounds fun right?

Note: You need access to the tenant search schema to break search experience globally, or employ this on your own site collections for mayhem and otherwise rendering yourself unpopular.

Breaking search by alias

Ever since SharePoint 2013 shipped we have been given the ability to add alias names to managed properties. The typical use case being you have a custom column in a SharePoint library which you want to use in search as a filter or refiner. You map the crawled property for your column ows_MyColumn to for example RefinableString100 and give it an alias explaining the content, for example DocumentStatus. This allows you to craft queries like DocumentStatus:draft instead of RefinableString100:draft. More readable and more descriptive.

So far, so good. What happens if you name your alias the same name as an existing managed property like Title or LastModifiedTime? It had never occurred to me this was possible, but what happens is that your aliases takes precedence and you have effectively taken over the values for those properties.


The left version in the above image shows the original values while the right shows the crawl date string for the title and last modified date via an alias on RefinableString100.


As you can imagine Microsoft Search and the built-in search experiences takes a dependency on what values to expect for many of the out of the box managed properties. Which means you need to take care when you use aliases to ensure you’re not using a name already in use. The good thing is that the fix is easy – remove the aliases and it all goes back to normal.

I’ll leave it as an exercise for the really curious ones to try this in a demo tenant using the out of the box search UI’s to see what happens.

Breaking search by mapping more crawled properties to existing managed properties

Take a managed property such as SPSiteUrl. The default configuration is to populate it with the value from ows_SPSiteURL, the site collection URL for an item.


There is nothing stopping you from adding more crawled properties to this list, but the option to only use the first and not all values is disabled. The result could end up with the managed property containing multiple values instead of the expected singular value – something built-in search UI’s might not have considered. Because why should you?

The fix is still easy, remove your added crawled property mapping and re-index the content.


If you didn’t quite get it – don’t do this, even if you can.

This post is about understanding how the alias and crawled property mapping features work. If someone performed a configuration without thinking it thru they can inadvertently break search experiences, and now you can fix it :)

Monday, August 26, 2019

Classic vs Modern and More Microsoft Search Questions Answered

imageOver the past several weeks there has been a number of community questions on classic vs. modern search in relationship to SharePoint and Microsoft Search across social channels. We selected the most common questions and created a Q&A article over at the Microsoft Tech Community to help answer those.

If you have comments or questions, scoot over to Tech Community and let us know.

Friday, August 23, 2019

I can see it! KQL in the house! HCWP love!

I’ve known this was coming for a while and I can finally see it in my tenant! KQL support for the highlighted content web part has finally arrived. Knock yourself out and surface content any way you want via search, (as long as the visuals cover your needs).

If you’re really crazy and bold, target the web part to a list/library and crank out your favorite CAML queries as well – not sure why you would ever go there though :D


Thursday, August 8, 2019

Update to using Microsoft Flow for approval of site pages

In May of last year I wrote a post which showed how you could implement approval of modern pages in SharePoint using Flow. That post was written before the edit experience implemented the Submit for approval button.


While the built-in approval is nice, Flow approval provides easy to use actionable messages which makes approving that much easier – no need for the approver to visit the page library to actually approve the item.

In my previous post I added a step to check for the Pending status of the page before invoking a Flow approval action in order skip the Draft and Approved states which should be ignored for the Flow itself. This means Flow will trigger more than actually needed – but that was the way to go last year.

Seems the SharePoint triggers have now been updated to support trigger filters, which means the steps can be optimized a bit.

Click the ellipses (…) on the trigger and pick Settings.


In the trigger conditions settings add the following to trigger only for items which are awaiting approval.



In order to use the content approve action you still need to get the correct ETag, which means the Get file metadata action has to stay.

A simple auto-approve Flow would look like below.


Happy Flowing!

Tuesday, August 6, 2019

Search nugget - Grouping property restrictions within a KQL query


Figured I’d alert you guys to a small nugget I was made aware of, and which I have officially documented at

The gist of it all is that you can now use parenthesis on property queries.

<Property Name>:(<Expression>)

As an example:

author:"John Smith" AND author:"Jane Smith"

can be rewritten as:

author:("John Smith" "Jane Smith")

The other cool side effect of adding () around the property value is that the term(s) will be lemmatized. The query title:page return matches with the exact term page only, while title:(page) also return matches for the term pages.

Head over to the docs to read all about it and check out some more complex samples. Start adding those parenthesis, and may the search be with you!

Note: Works for SharePoint Online and SharePoint 2019 only.

Tuesday, June 11, 2019

SharePoint Search Query Tool v2.8.4

Photo by Jason Wong at Unsplash

Get it at

Not a lot happening for this version - mainly UI improvements and support for query history.

Happy searching!

Friday, June 7, 2019

PnP Modern Search Web Parts June 2019 release is out

Get it at

Modern Search Web Parts v3.4.0.0

  • Updated to SPFx v1.8.2
  • Added query language setting
  • Translations
  • Improved loading placeholders
  • Improved hash paramater change handling

Modern Search Custom Renderer v1.0.1.0

  • First binary release
  • Includes example custom code renderer when Handlebars is not enough

Sunday, June 2, 2019

The conspiracy is real!

..or “I believe in Microsoft Search” :)

In February of 2016 I wrote a post titled "I Want to Believe" - Is Microsoft abandoning the enterprise features of enterprise search? where I discuss how Microsoft seems to have abandoned enterprise search, but I still wanted to believe they had not.

Ever since I wrote that article over three years ago I have slowly been building up to write a follow-up – trying hard to find the right framing for my thoughts.

For those who know me, they know I haven’t spent particularly much time on search related work the past years. Why? I have just about only been working with Office 365 and SharePoint Online and tinkering too much with search online has seemed like a bad idea – especially after the launch of modern SharePoint in mid-2017. My advice to clients has been to not spend too much effort on configuring search and see where things are going in the platform as you cannot control much in terms of functionality and user interfaces.

And just as I was about to write my follow-up article in January of this year about having lost the faith, Kathrine Hammervold of Microsoft contacts me for our semi-random-annual coffee chat on “the state of search”. This has typically been an informal chat where I get to give my feedback from the customer/consulting side of search. Except, I was not let in on the new agenda.

My very own Microsoft Search t-shirt and shoe laces!
Over the years I’ve been asked numerous times if I would consider joining Microsoft. It has always been unofficial as part of random conversations, and honestly I’ve been very comfortable working on the “outside” for Puzzlepart. This time around it was very concrete; Kathrine asked if I would be interested in joining the search team!

From what she told me over coffee I was very much intrigued on “the state of Microsoft Search” and my spirits instantly rose. Maybe I could help form the future and have an impact?

I have been with Puzzlepart since 2011 and I so love my job and my freedom. I had no intention of switching jobs what so ever that Tuesday afternoon, but after much thought and discussions with great friends in and outside of Microsoft I decided I had nothing to lose and everything to gain.

Monday June 3rd I’ll be starting my new adventure in a new office, working with many of the people I already know inside of Microsoft as well as get to know a lot of new smart people. Quitting Puzzlepart was certainly not easy and has been a tough choice emotionally. It’s by far the best place I have ever worked and these past 8 years have just flown by. I love the people, I love the work, and I love Puzzlepart’s approach to clients and projects – it’s possibly one of the best Office 365 consultancies to work for. Everyone matters and everyone has the ability to shape their future and to be heard - but be prepared to juggle two to three clients at any one time (cheaper for the client, for fun for you :)  And if you follow my blog you know Puzzlepart share a lot of the things they create for absolutely free on GitHub, as well as contribute to the Office 365 Patterns and Practices (PnP) work.

Which leads to: I honestly believe in Microsoft Search!, and that customers can get back some of the old flexibility we used to love in a modern way. In addition, modern AI driven features are constantly added to the mix, making search and search driven features even more ubiquitous than ever. It’s not about the tech, it’s about making the people who use the Microsoft platform even more efficient and innovative in their jobs.

“May the search be with you!”

Wednesday, May 15, 2019

Approve a document in Teams using Adaptive Cards and Flow

Co-incidentally the same scenarios often appear simultaneously from different people at the same time, and this is one of them.

I’ve been assisting with random comments to a client who wants to start an approval on a document, and have that show up as a card with Approve/Decline buttons in Teams. And yesterday the good SharePoint/Flow man himself Chaks at Microsoft reached out with a similar scenario.

Chaks wanted to build a bot for this, and I asked if he had tried the Adaptive Card action in Flow, and have card buttons trigger an approval/decline action via a HTTP trigger. Turns out that adaptive cards via Flow in Teams does not support Action.Http. End of story.

Here I am, having told a client this should be easy, and Chaks telling me I can’t do it. Being me, that’s not acceptable, of course it can be done – and turns out my ego was right this time :D (it’s not always)

Start the approval Flow from SharePoint.

Adaptive card in Teams.

Important: Enable Major, minor versioning and approval on the document library. And I have not put any thoughts into licensing of actions in Flow if any for this scenario.

How??? Let me show you!

Friday, May 3, 2019

Gotcha in Microsoft Flow when modifying properties on a newly created file

This one is a common task, something I've set up a quadrillion times with workflows and event receivers in SharePoint over the past decade or so. And now the time has come to using Microsoft Flow.

The scenario is that when a file is created, you have a piece of business logic which should set metadata on the file. It could be a status flag, a serial number - the business cases are many and diverse.

Read on, young apprentice (you know who you are :) )

Thursday, May 2, 2019

How to: Creating modern page templates, and retrofitting old pages as templates

Microsoft is in the process of rolling out modern page templates, which is something we've been waiting for for a good long while now. And finally the time has come :)

I've seen it in most tenants, but not all - so be patient as it's trickling in.

If you haven't tested this yet I'll do a quick walk-thru.

To create a template you perform the following steps: Create a new modern page, add all there is to it, hit publish, and you get the option to save the page as a template as seen in the image below.

Note: The option to save as a template only show the first time you publish, but the option is available if you click the Promote button on a page as well.

Once you have created a template it will show up when you click New page from the menu on any existing modern page (it does not show while in the Site Pages library or the cog wheel Add a page at the time of writing).

What if you have existing pages you want to use as templates? One option is to start a new page with Copy of this page, and follow the steps above. Then delete the original page you used as a template as well as your new copy.

But as we're all savvy modern users we know it's simpler. If  you look at how the template feature is actually implemented, you will quickly get the drift. Once you create your first template a folder named Templates is created in the Site Pages library and any page in this folder will show as a template.

Note: If the file you move has been published as a major version at one time or another, the template will also show in search. Same goes if you turn off minor versioning on the Site Pages library. So you might want to create a template from that file instead, and then delete the files still....

This means you can retro-fit existing templates in a site performing the following steps:
  • Create a dummy template in order to have the Template folder created and enabled for templating.
  • Select the page you want as a template, and drag/move it to the Templates folder, as there is no move command on the Site Pages library.
  • Navigate to the Templates folder and open the page and you see it's now been templaty'fied
When you now want to create a new page, the template will show up as easy as corral balls!

For the techies out there

A big thank you to Erwin Van Hunen for helping on this one.

If you manually want to set up the templating feature, say in a provisioning scenario, do the following:

  • Create a folder in Site Pages (name it whatever you want) and record the unique guid of the folder

    $f = Get-PnPFolder  SitePages/MyTemplates -Includes UniqueId
  • In the property bag of the Site Pages library, set vti_TemplatesFolderGuid to that guid

    Set-PnPPropertyBagValue -Key "vti_TemplatesFolderGuid" -Value $f.UniqueId -Folder "SitePages"

Tuesday, April 23, 2019

Disable Event Firing when Flow updates a SharePoint list item

There’s a lengthy discussion over at to have a Flow trigger on a SharePoint item being modified, and then be able to update that same item in the workflow without causing it to re-trigger, causing a possible infinite loop.

The workaround posted so far is to check on a specific field if you are to update the item or not. This causes Flow to fire twice per item, one for the actual update, and one where it skips the update based on some status logic.

Melissa Hubbard has a post on the workaround solution over at THE INFINITE LOOP: WHAT IT IS AND HOW TO AVOID IT.

It is also possible to use the ValidateUpdateListItem REST API as well, but you need to ensure you get the dates formatted correctly. I could not make it work for Norwegian locale, but once setting the locale to English I got it working. Examine the output of the action after a test run to see if dates had issues or not.

A big thank you to John Liu for pointing this out, as I missed the trick of setting the date when testing this API when researching this post.

As an update to the JSON payload used in John's post, set bNewDocumentUpdate to true, if you don't want to add a new version to the item you are updating (kind of counter-intuitive).

[Original Post]

The underlying issue causing this behavior is that any update to a SharePoint item will trigger an update event for the list. EXCEPT if you use a method called SystemUpdate, which is only available via the JSOM/CSOM/Native SharePoint API’s, and not the REST API.

This quickly becomes very technical, but until the SharePoint Flow connectors support the ability to update using a System Update, this is what we have to deal with. It is certainly possible to overcome this issue, but it involves a bit of XML which might throw you off. If not, read on.

Gotcha in Microsoft Flow when handling SharePoint list item attachments

I’ve written a couple of these, where I in PowerApps allow the user to upload attachments to a list item. This feature can typically be used to upload documents or photos from the end user.

While list attachments work fine they are often easier managed in a separate document library, or perhaps you want to perform some other action on them. And this is where Flow comes into the picture. When the item is saved in SharePoint associate a Flow which triggers on new items in the list.

What is important to note is that when list items with attachments are created, the item is first created, and then each attachment will be a subsequent operation. When this action is performed using a phone or tablet the attachment upload might take some time, and Flow might very well trigger before all the attachments are done uploading - the effect being that Flow will miss some of the attachments, and your business process can miss some important data.

Friday, March 22, 2019

Exposing a Group calendar in Teams (also for external members)

Every Microsoft Team is built upon an Office 365 Group, and each group has a group calendar. Unfortunately external users don’t have direct access to this calendar. There are a couple of ways to add a group calendar to Teams as a teams tab, but currently there is only one configurable approach which works for external members of a team/group.

(The non-working option is to add a teams tab which point to the URL for the groups calendar.)

The steps involved are to go to the Teams modern team site, create a new page, add the calendar web part to that page, and then link to to that page as a teams tab.

Here I’ve create a page called calendar.

In the Microsoft Teams client, add a SharePoint tab, pointing to this page.

When an external user visits the team, the calendar displays nicely in the tab, as it would for internal users.

Note: Newly added users to a team might not see the calendar right away as it takes a little bit of time for permissions to synchronize

Wednesday, March 20, 2019

A simple solution to implementing proper back functionality in PowerApps

When navigating between screens in PowerApps you use the Navigate function. There is also a Back function which takes you to the previous screen. The caveat with Back is that it doesn’t build a navigation history, but remember the previous screen only. This means that if you go from screen 5 to 4 using Back, then the next Back call will take you to 5 again, not screen 3.

Do I really need to think about this?

Puzzlepart introduces Hook me up! – an anchor part for modern pagers

In January of 2018 I wrote a post showing how you could use the modern script editor web part to add a jump anchor to a modern page. Of course, you should shy this web part due to possible security risks (unless you really really know what you are doing).

Last night Theresa Eller was looking for a proper solution to this on twitter, so I whipped up a small web part which adds an invisible span tag to the page, which you can anchor to. If you set scrolltome as the id, you can reference it when creating a hyper link in the text web part.


This time around I made the code compatible with both SharePoint 2016 and 2019 as well.

Go download the sppkg file from and install it where needed.

Monday, March 18, 2019

Fetch a Bearer token in SharePoint context to be used with a back-end service

(The post image has nothing to do with bearer tokens, but the Lego 1967 Mustang GT I finished building is just freakishly cool!)

I’m working on a solution which has a small UI created using the SharePoint Framework. This UI will make an authenticated call to a back-end service, which again has to read some data from a SharePoint list for validation.

The easy approach would be to read the validation data in the UI, but this would lead to a potential security hole, disclosing the verification mechanism. I could also have read the SharePoint data using app-only permissions in the back-end service, but this adds one more moving piece.

Thus, I ended up with fetching a valid Bearer token for the logged in user, and passing that along to the back-end service, which in turn can use it for SharePoint authorization.

The code itself is fairly simple from within the SPFx web part.

const provider = await this.context.aadTokenProviderFactory.getTokenProvider();
const token = await provider.getToken('https://<tenant>');

Took me a few tries, but pass in the root URL for your tenant and you get a token you can use for future calls against any SharePoint resource (as long as it’s valid).

Tuesday, March 5, 2019

Governance and consciousness around handling Teams and Groups

foosball table shallow focus photography

I have worked in the space of content production and collaboration for quite a few years now. Along this journey new tools and technologies have arrived to help us better manage the content being produced. At the same time content production increases, and it’s no easy feat for neither technology nor people to keep up with the constant battle of managing content the right way, and making sure the right content is readily available and findable.

To simplify matters we can divide the problem into two.

  1. How do you make sure content is stored correctly according to business rules and regulations which might apply
  2. How do you make sure stale/old/obsolete content is removed and not hoarded to ensure valid content is surfaced

I have previously written about why and how you can take control of Teams and Office 365 Group creation in Office 365, and approaches automating the lifecycle management of Teams and Groups.

There is no one solution which just solves everything and each business has to form their own opinion on how they want to use technology to improve the quality of content stored in their organization. The only known is that the longer you wait before deciding on a path, the harder it is to fit the solution on top of existing content afterwards.

Once you have decided what your governance plan should be, you need to figure out what parts can be automated, and what parts require human actions – and how can you ensure humans take the correct action. If being asked if you should keep or delete a Team/Group if it seems inactive, the default human response is probably to keep it, as then you won’t get blamed for deleting anything important. A better process might be to make sure employees take ownership and are made accountable of their content – to filter out the good from the bad – and perhaps move the good content to another permanent storage.

Or go the easy route and let anarchy take hold and hope technology by itself will solve all your problems in the long run – any plan decided is better than no plan at all :)

If some of this sounds interesting, feel free to attend my session “What Options do You Have to Govern the Lifecycle of Office 365 Groups and Teams?” at the SharePoint Conference in May:

Office 365 Groups and Teams introduce many workloads such as document management, tasks management, and chat logs. Built into the Office 365 platform your organization has many tools and functions available to help control how information is governed and to help you control the lifecycle of the information stored within the groups and teams.

The goal of my presentation is to show what tools are available in the Office 365 suite to help with lifecycle management and to show how you can use them to ensure a healthy environment with reduced information bloat while still maintaining information control and integrity. Some of the functions are available in different administration UI’s, but for the IT Pro’s loving PowerShell out there, most of it today is available via PowerShell and the Microsoft Graph.

Using admin UI’s and PowerShell I will dig into some of those capabilities and show how you can get hold of the information you need in order to implement your business rules and requirements for lifecycle management of Office 365 Groups and Teams.

Save $50 and register via today!


Happy content controlling!

Post image by Alex Sajan at Unsplash

Thursday, February 28, 2019

PowerApps user filtering gotcha against SharePoint


PowerApps has for a long time supported filtering SharePoint data based on a person – the typically scenario in a PowerApps being that you want to fetch data rows based on the logged in user in PowerApps.

If you look at the post they have a sample along the lines of:


Issues is a SharePoint list and AssignedTo is people field, containing the person an issue is assigned to.

The issue with this sample is that User.Email() actually returns thee user principle name (UPN), and not the e-mail address, and the value is also always in lower case. For most users this does not represent a problem, but for some it might. If your e-mail address is, the UPN could be, thus the filtering would fail as it’s case sensitive.

The solution is to filter on the Claims property for a person field in SharePoint instead of Email.

What I typically do is that in the application OnStart event I set a global variable where I prefix the UPN with the default claims prefix.


The filter command then turns into:


Happy PowerApp’ing!

Monday, February 11, 2019

Locate pages where a particular web part is being using on modern SharePoint sites

close up photography of LED bulb on sand

This post was inspired by, but I’ve simplified things a bit as some of the steps are not needed. I also opted to use PnP PowerShell.

There is no defined API to find usages of specific SharePoint Framework web parts on modern pages. But fortunately for us the id of each web part is included in the searchable content for modern pages (no need to map up a particular refinable string for this as per the inspired post).

Note: Only pages you have access to will be listed – if you need all pages you can elevate search permissions using app-only permissions, which is (dangerous) different story.

Tuesday, February 5, 2019

Eh??? Ok? Beware of casing when using automatically created managed properties in search


I’m not sure this is intentional or not, but something you really need to pay attention to if you develop search based solutions in SharePoint Online (afaik it does not impact search for on-premises).

Up until recently(?) all managed property names were case insensitive. The change now is that automatically created managed properties based on site columns ( – those ending in OWS<something>, are now case sensitive. The others work as before.

If you for example create a site column of type number named MyFoo, the automatically created managed property for this column will be MyFooOWSNMBR. Previously you could retrieve the value of this property, or query it by entering any casing of the name.

This meant that MyFooOWSNMBR:10 and myfooowsnmbr:10 were equal queries. But not any more.

If you use any casing but the one listed in the search schema it will be treated as an unknown managed property yielding no results or values on retrieval.

Which means if you are like me and typically type all managed property names in lowercase you have work to do to fix it all up.

This information was found at

Thursday, January 24, 2019

A no-nonsense solution to implement cascading dropdowns using PowerApps as a custom form in SharePoint

Search for “powerapps cascading dropdowns sharepoint” on the interwebs and you will find a bunch of ways to get this to work, but I dare to say that the solution I propose is by far the easiest and most elegant. And a big thank you to my colleague Thomas who helped along with this one.

My sample is super easy. I have three lists, Countries, Cities and Customers. Cities has a lookup to Countries, and Customers has a lookup to both Countries and Cities.


By default the input form looks like the image below, where all cities are shown regardless of the selected country. But this is easily fixed.


Monday, January 7, 2019

Introducing the SharePoint REST API v2.0


For as long as REST has been supported in SharePoint the endpoint programmers have used is http://server/site/_api/ or for those of us who left on-premises years and years ago.

Now Microsoft has given us a v2 endpoint for the REST API. This has sort slipped under the radar, but I’m happy to announce that it’s there, it’s supported, and you can use it!

But wait, what is this v2 API, and why should I care or use it?

Friday, January 4, 2019

Eh??? Ok? Be aware of a modern change which can impact your classical way of displaying search results

My colleague Tarald recently discovered that when looking at the managed property CreatedBy for modern pages where you have filled in the author byline, it will show the primary e-mail address, display name, and claims token for that user (and the claim includes the user principle name). | Bar, Foo | 693A30232E667C6D656D626572736869707C666F6F2E62617240636F6E746F736F2E636F6D i:0#.f|membership|

Maybe not a big deal, but since forever, this managed property has contained only the display name of the user, nothing else. I’m not saying it’s a bad thing to give all the data as that disambiguates people with the same name, but what’s bad is changing default behavior which has been consistent for a long time.

The culprit to it all is that Microsoft has decided to map the crawled property ows_q_USER_AuthorByline as the first property when populating the managed property CreatedBy. The same mapping is done to the AuthorOWSUSER managed property, which is ok, as this property always had all data included.


The best option in my opinion is for Microsoft to remove this mapping, and create a new AuthorByLine managed property instead. That’s the way SharePoint developers have been taught to do when introducing new values. You can also change the mapping yourself, but that might mess up some oob web parts.