Shared Modules In Angular Apps: Providers Best Practices And What Does `forRoot()` Do?

When you write a shared module for your application, that contains stuff you use in other modules in the same app, you typically want all the services in that module shared only once.

If you just put the services in the providers property of the shared module’s NgModule() decorators, you might get weird cases, especially with lazy loading, when it feels like there’s more than one instance of the service. This is bad if you want to have shared state.

So, there is a better way to write your shared modules:

import {NgModule, ModuleWithProviders} from '@angular/core';
import {CommonModule} from '@angular/common';
// ... other imports

export const providers = [
    // ... your shared services here
];

@NgModule({
    declarations: [...],
    imports: [
        CommonModule, 
        SomeLibraryModule,
        ...],
    exports: [
        SomeLibraryModule.forRoot()
        ...
    ]
})
export class SharedModule {
    static forRoot() : ModuleWithProviders {
        return {
            ngModule: SharedModule,
            providers: [...providers]
        };
    }
}

The forRoot() pattern / convention is very common in libraries, and you’ll see it in things like ng-bootstrap and others. The name isn’t special for the compiler / framework, but it’s a common pattern.

When using these, in the imports section you can just import the module itself (which gives you any declarations needed like directives etc), and in the exports use the forRoot() version of the module so that it’s available for consumers of your shared module.

Then in your other application modules you can add SharedModule to their NgModule‘s imports normally, except for the AppModule.

The AppModule will be the only place where you add SharedModule.forRoot(), like:

Then in your AppModule, import it as:

@NgModule({
    declarations: [...],
    imports: [BrowserModule, SharedModule.forRoot(), ...],
    ...
})
export class AppModule {

}

There is one exception to this though. Your tests.

If you are writing any unit tests where you are importing the SharedModule, you will probably need to import the module with its providers, because there is no AppModule in the test.

Something like:

TestBed.configureTestingModule({
    imports: [ SharedModule.forRoot(), ... ]
})
...

If you haven’t already, have a look at the NgModule official documentation. There’s a main guide, and an FAQ page.

And of course let me know if you have any questions / problems.

Successfully Upgrade Your angular-cli App (Beta 28 & Below) To The Latest @angular/cli Beta


Have you had issues moving from angular-cli beta 28.3 or earlier to the newer versions of the CLI?

Try these steps then!

Global Dependency

This one is as easy as:

npm rm -g angular-cli @angular/cli
npm cache clear
npm i -g @angular/cli

Specific Project

Note: You do NOT need to have the CLI installed globally for this (although it’s a good idea).

First, ensure you have an npm script in your package.json file that looks like:

"scripts": {
    "ng": "ng"
    // ....
}

In this tutorial I’ll replace ng calls with npm run ng -- (note final space ) for those people who may not be able to upgrade their global package.

Now, let’s get to real work.

Commit everything you have in git, then:

npm rm angular-cli @angular/cli
npm cache clear
rm -rf node_modules
npm i -D @angular/cli
npm run ng -- update

Accept all files from update (which used to be called init) other than app module and component, especially (but not limited to) angular-cli.json, polyfills.ts, package.json and main.ts.

Then go to git undo any unwanted change (deleted packages from package.json, missing scripts or files from angular-cli.json, etc). Undo entire app module and component files if you accepted them by accident.

Then

npm install
npm run ng -- build

And you can go roll with npm start / npm run ng -- serve.

All good!

Use Yarn Package Manager In Your Angular CLI Projects

Yarn is an awesome tool to reduce the time it takes to install large NPM packages like the Angular CLI. And the Angular CLI is the best tool to kickstart and manage your Angular 2+ projects.

You can use them together, and it’s very easy.

Initial Setup

First, you install Yarn. If you have it installed already, ensure that you have version 0.19.x at least to avoid issues with global packages. You check your Yarn version by running:

yarn --version

Then you need to ensure that the folder where Yarn writes the global packages executable files.

On Windows, the MSI installer should do it for you. For Mac, check the “Path Setup” part in the installation page.

Once done, ensure to open a new terminal after the installation, and test it.

To find what folder to look for:

yarn global bin

Then run echo $PATH (Mac) or echo %PATH% (Windows command prompt) to get the PATH variable and check it.

Installing Angular CLI

OK, so yarn is installed, and it’s installed correctly. Let’s get Angular CLI:

yarn global add @angular/cli

That’s it!

Adding To A New Angular CLI Project

Starting from beta 31, Angular CLI added native Yarn support.

When you create a new project, the CLI goes and runs npm install for you by default. You can tell it not to by passing a --skip-install flag (-si for short) like:

ng new test-project --skip-install

Note: The option was called --skip-npm / -sn before beta 31.

But then you’ll have to go run Yarn yourself

cd test-project
yarn

Running yarn by itself is similar to npm install. It’ll read your package.json file and add the packages to node_modules as needed.

Or… you can just tell the CLI to use Yarn instead of NPM!

ng set --global packageManager=yarn

This way, you don’t need to do anything special when creating new projects. Just go with ng new test-project with no special flags, and the CLI will use Yarn to install the project packages, unless you specify --skip-install.

This is a user-level setting. It does not affect the generated project in any destructive way. It still has a package.json file (because Yarn works just fine with that), and anyone who doesn’t have Yarn can just run npm install.

More on that below. Before that, let’s ensure that everything worked correctly by running npm start or ng serve etc.

All good? Awesome!

Bonus: A Note About Git

When the Angular CLI creates the project, it initializes it as a git repository and git adds all the files it generated. After the Yarn install, you’ll find another file yarn.lock that’s not yet added.

Yarn team recommends adding the file to git, so, you can do just that, and then commit the result as the new project.

git add yarn.lock
git commit -m "initialize new project with Yarn and Angular CLI"

When you push your repository to a remote server, and someone else pulls it, they can run yarn, or simply npm install (because the package.json file is still there and updated), and get going with the project.

Conclusion

Hopefully that was as simple as you expected it to be. If you have any questions, you can just drop me a comment here, or use any alternative way mentioned in the video.

Don’t forget to sign up for my newsletter so that I can share with you all the resources I use to learn this stuff and more.

Cheers,

Use DIV, TR, or any other tag instead of FORM tag in Angular 2

I got this question in one of my tech Facebook groups today:

In Angular2, Is there anyway for dealing with forms rather than form tag??? As In AngularJS 1.x, there was <form> and <ng-form>.

Is there something like that in Angular2 or we must deal with form tag?!

And the answer is: Yes. It’s possible to create forms without the form tag in Angular 2, with a gotcha…

Here’s how:

Template Driven Forms

If you look for the selector for ngForm directive in Angular2, you’ll find it like that:

form:not([ngNoForm]):not([formGroup])
ngForm
[ngForm]

Note that last one. Any element with ngForm tag <ngForm ...> or attribute <any ngForm ... > should work.

Reference

Reactive Forms (Model Driven)

The selector for formGroup directive is:

[formGroup]

Which also means that any element with formGroup attribute should work.

Reference

Gotcha

There is a relatively-big bug with non-form elements used as forms in Angular 2. The submit events do not work.

The implementation is just not as mature as Angular 1.

I have raised a bug here in March, but it’s probably a low priority:

@angular/angular#7807

You might be able to comment on it stating your scenario to bring it some attention.

Angular 2: Here’s how to use jQuery in an Angular CLI project

Please do not take the post as an endorsement of using jQuery with Angular 2. I do not think it’s a good idea. Most stuff you use jQuery for cam be done directly from Angular 2.

However, there might be legitimate reasons for using jQuery, like using jQuery widgets and plugins that do not have a non-jQuery based equivalent. If you are facing that, try this guide:

If you are using the Angular CLI (my personal recommendation), you can use jQuery with Angular 2 in very few and easy steps as follows:

First: Install jQuery, the actual library


npm install jquery --save

Then: Install jQuery TypeScript autocomplete


npm install @types/jquery --save-dev

Finally: Go to the ./angular-cli.json file at the root of your Angular CLI project folder, and find the scripts: [] property, add this inside it:


"../node_modules/jquery/dist/jquery.min.js"

(or use the slim version if that’s your cup of tea, keep the rest of the path as-is)

After that, jQuery will be available for you as a global variable. You can log jQuery’s version (which is available as jQuery.fn.jquery) to ensure it’s working brilliantly.

How To Get jQuery To Work With Angular 2 CLI – Webpack Edition

I wrote a post yesterday that talked about:
Using Webpack with Angular CLI directly from official Github source
The post seemed to get a bit of traction on twitter, and among other feedback, I got an interesting question in a direct message:

Hi Meligy, Have you tried importing jQuery in Angular-CLI webpack branch project anytime??

Well, turns out I didn’t. I expected it to be just a require(...) / import ... line away. With Webpack, you often don’t need much more than that.

But then when I tried, I found a problem after another, which turned to be very specific to jQuery. It’s an edge case, but for the library the community size of jQuery, it’s worth showing:

A Working Configuration

First, install jQuery:

npm install jquery

Then install jQuery typings:

typings install dt~jquery --global --save

Adding a test

Then you can modify src/main.ts to include and test jQuery:

  • Add the import:
import * as jQuery from 'jquery';
  • Change the bootstrap(AppComponent); line to:
jQuery(() => bootstrap(AppComponent));

Running it

You can go ahead and run ng serve or ng build -prod. I saw what looked like a TypeScript error in the output, so, go run just that:

tsc -p src/

You’ll get an error:

src/main.ts(11,12): error TS2345: Argument of type '() => Promise<ComponentRef<any>>' is not assignable to parameter of type 'string'.
typings/globals/jquery/index.d.ts(3218,13): error TS2403: Subsequent variable declarations must have the same type.  Variable '$' must be of type 'cssSelectorHelper', but here has type 'JQueryStatic'.

Explaining the problem

This error is because of a conflict between Angular Protractor and jQuery. Angular Protractor defines a global “$” that you use to write your Selenium element selectors nicer, etc. Normally you don’t write real jQuery code in a Selenium test, but Protractor is included in the TypeScript definitions that are included in the entire application.

Working around it

A temporary workaround is to manage the typings files for the website (src folder) and End To End tests (e2e folder) separately.

Each of the the folders have a typings.d.ts file that has (possibly among other things), a typings reference to the root level typings folder:

/// <reference path="../typings/index.d.ts" />

The problem is that the typings/index.d.ts file looks like:

/// <reference path="globals/angular-protractor/index.d.ts" />
/// <reference path="globals/jasmine/index.d.ts" />
/// <reference path="globals/jquery/index.d.ts" />
/// <reference path="globals/selenium-webdriver/index.d.ts" />

Now, we can’t have both angular-protractor and jQuery in the same file, but we cannot modify typings/index.d.ts directly because every time we run typings install, the file will be overridden (and many even add the typings folder to .gitignore).

What we can do though, is replace the reference to it from src/typings.d.ts and e2e/typings.d.ts. When we do, we need to account for path change, we’ll need to prefix the paths with ../typings/ to point to their correct location.

In src/typings.d.ts, we replace the ../typings/index.d.ts reference line with:

/// <reference path="globals/jasmine/index.d.ts" />
/// <reference path="../typings/globals/jquery/index.d.ts" />
/// <reference path="../typings/globals/selenium-webdriver/index.d.ts" />

In e2e/typings.d.ts, we replace the ../typings/index.d.ts reference line with:

/// <reference path="../typings/globals/angular-protractor/index.d.ts" />
/// <reference path="../typings/globals/jasmine/index.d.ts" />
/// <reference path="../typings/globals/selenium-webdriver/index.d.ts" />

And that should be it. No errors n TypeScript compilation, and running ng serve, then opening http://localhost:4200 shows us that the app still works, with the bootstrap() call now executed from jQuery’s ready call – which we added only to make sure it works!

Run ng build -prod and check the output in dist. You’ll find that it also works well.

Remember, this is only a workaround!

A drawback of what we did is that every time we add typings for a new library using the typings command, we’ll have to add a reference to it manually in src/typings.d.ts and/or e2e/typings.d.ts depending on fit. It’s easy to forget the manual step and get confused.

Luckily though, this is an edge case. Most of the libraries will not have such conflicts (see, that’s why everybody says modules are cool and globals are bad!). For most libraries, all you’ll need to do is to require(..) / import ... a module from the library, and everything will happen magically. Thanks to Webpack, you’ll not even need to setup vendor or systemjs config etc. Check my previous post for more information.

Other ideas

A few other starters seem to have the same problem. One other way to tackle it is to exclude the path typings/globals/angular-protractor from the Webpack config, but currently, I can’t see this config exposed from the Angular CLI. I’m sure it’ll be there once it’s final etc., but it’s not there now.

Another idea is to have a noConflict typings version of jQuery. There’s a pull request to DefinitelyTyped registry to include that, but it’s abandoned and closed at the moment. You can try calling the exact file via typings as a github~ file not dt~. But obviously you miss potential updates.

The best thing that can happen is that the Angular CLI would bring the separation of typings for src code and e2e tests built-in, which may or may not land in the CLI. Let’s see!

Should you use jQuery with Angular 2 at all?

I think the answer is: avoid it if you can.

I’m currently working with a team that has it included, and it was mostly due to needing some UI widgets that are only available for jQuery. I’m hoping that this is going to change with more UI widgets coming standalone, and easy to wrap in Angular 2 components / directives. Many widgets are becoming available with the Angular 2 wrappers already, like the lovely ng2-bootstrap collection.

Use Angular 2 CLI with Webpack Directly from Github Source Code

You have heard the rumour, that Angular CLI is going Webpack. And it’s true. The CLi is replacing broccoli + systemjs with Webpack.

Update 1 (See Update 2 for latest)

The Webpack feature has landed in master GitHub branch!
It’s not on NPM yet (subscribe to my newsletter to get updated when it’s), and it’s in active development.
So, you might still find benefit in trying it out directly from GitHub sources.

Update 2

The Angular CLI has landed on NPM, but you need to call it in a special way:

If you installed Angular CLI before, go

npm unlink angular-cli
npm rm -g angular-cli
npm cache clear

Then to install the Webpack version:
npm install -g angular-cli@webpack

Gotcha

When you run `ng new some-app`, and go inside it and run `ng serve`,
if you might get error like:

No angular-cli-build.js found. Please see the transition guide: https://github.com/angular-cli/angular-cli/blob/master/TRANSITION.md#user-content-brocfile-transition.

To solve this error, you can go to `package.json`, and change
`”angular-cli”: “^1.0.0-beta.11-webpack”,`
to `”angular-cli”: “1.0.0-beta.11-webpack”,`
(remove the `^` from the version)
Then run `npm install`. It should work after that!

You can also skip the initial NPM install using the param `–sn` (skip npm):

ng new my-app --sn

Then go fix the package.json file, and run npm install manually, so it only runs once.

Git or Npm?

Depending on how safe you want to go, you might find the master branch of the CLI often having features that are very interesting. This is always the case of course, but it’s more severe as the Webpack move in active as it’s now.

To check the difference, see the release change log vs the git commit log.

I’m not 100% sure of the exact reasons that convinced the team to go this way, but as an end user of the CLI, I expect a few benefits:

  • Easier inclusion of 3rd party dependencies in the build output.

    Instead of having to fiddle with vendor.js file and systemJS config, you just call require("dependency"); and be done with it; where dependency can come from local directory or NPM package, and can be any TypeScript / JavaScript file, or even a CSS / HTML / image file!

  • Easier tree-shaking

    Which means removing parts that are not used in your program from the build output. Angular is betting big on this (mostly via rollup.js library, but possibly via Google closure compiler in the future). Webpack has a few features built-in around this as well.

  • Easier (seamless) Webpack integration

    The current official Angular2 Webpack cookbook says you need to call require("some-name.component.html") in your component’s templateUrl, which is silly because it’s Webpack-only syntax.

    Having tried the Webpack version of the CLI, I’m happy to report that you don’t need to do that anymore.

How to use Angular CLI directly from Github?

So, now that we know why Webpack might be interesting to bring to the CLI, let’s talk about how you can try it even before it’s officially released. That’s if you feel adventurous and want to be on the bleeding edge of course!

Normally you install the Angular CLI npm package by calling:

npm install angular-cli -g

Which makes the ng command available anywhere.

Instead, of that, you need to do this:

git clone https://github.com/angular/angular-cli.git
cd angular-cli
npm install
npm link

Here’s what this will do:

  • Clone Angular-Cli and checkout the webpack branch

    Note that the same method can be applied with the webpack branch where this feature originally landed.

    You just need to call git checkout Webpack (assuming a branch named “webpack”) before npm link.
    This should automatically track the remote webpack branch (as in origin/webpack) if you have a fairly recent version of git.

  • Use the package information in package.json file inside the repository to build and globally install angular-cli NPM package from the contents of the repository.

    To make sure this process succeeds, we installed all the dependencies the repo has. I’m not 100% sure this is needed, but to be safe.

Now when you run the command ng, it’ll come from the version you just downloaded via git. In the future, when you want to update this version you just:

cd angular-cli
git pull
npm install
npm link

Let’s use it!

Run:

ng new sample-wp
cd sample-wp

If you try to run ng serve or something similar now, you’ll get an error. This is because ng new downloads a version of the angular-cli into the newly created folder. This is the online version available on NPM directory not the one you have offline, so we need to switch to it.

Ensure that you are inside the new folder created, and call:

npm link angular-cli

Note the difference:

  • When we were inside the git repository and want to use as a global depdendency, we called npm link with no arguments.
  • When we were in a normal project folder, and wanted to replace the local folder version of the depdendency, we called npm link angular-cli, where angular-cli is the name of the package we globally linked before.

Easier Way

Linking can now happen automatically by changing your `ng new` command to:

ng new sample-wp --link-cli

After that, you should be able to run the application:

ng serve

You’ll notice a new output that’s different from what you used to. This is webpack output.

The website will still be available at the usual port 4200. Go to Chrome and open http://localhost:4200 to see it. Modify the app component and see live reload working as usual.

Other things will work normally, like generating components, etc. Check the following command though:

ng build -prod

If you look at the generated output in dist folder, you’ll realise that it’s slightly different due to removal of systemjs.

The size is still quite big at the time of writing though, but this is the area we expect to see more love going to before Angular 2’s final release.

That’s it

Let me know if you enjoyed this post. Say hi on twitter, and sign up to my article updates newsletter.

Bonus Content: Using jQuery

After this post got a bit popular, someone asked me about getting jQuery working with this setup, which showed a particular edge case around protractor and jQuery conflict. Although I wouldn’t generally recommend using jQuery and Angular 2, wrote about how to workaround this conflict, and how to get jQuery to work with Angular CLI and Wepack here.

How to use Angular 2 with ASP.NET 4.5+ / ASP.NET MVC 5

I got the following question in my ng-sydney AngularJS usergroup:

How to setup ng2 with Vs2015 for asp.net like mvc/web API?

While many blog posts answer the question for ASP .NET Core, very few answered it for ASP.NET 4.5 / ASP.NET MVC 5. So, here’s what I tried, and seemed to work.

Create a new project in Visual Studio

I found this online project template template Angular2 Mvc5 sample application, and it worked pretty well.

File -- New Project

Run the sample you get to see the output working.

Also, read the template page for workaround to potential issues with Node.

Upgrade the outcome

Unfortunately, the template only gives you Angular 2 RC1 work, with the deprecated router.

Luckily, it’s not too hard to upgrade it!

package.json

If you go to the official Angular quickstart, which you can reach by going to angular.io, and clicking “Get started”), you can find the package versions you need in 2 ways:

  1. Clicking “live example”, which takes you to the Plunker example page, you can get the latest versions of Angular 2 packages in the system.config.js file.
  2. Scrolling to Step 1 – b, which shows a package.json file you can just copy the dependencies section from.

Once you figure out the version numbers, you need to apply these to the package.json file in the root of the web project, here’s what the dependencies piece looks like for me, for Angular 2 RC 4:

  "dependencies": {
    "@angular/common": "2.0.0-rc.4",
    "@angular/compiler": "2.0.0-rc.4",
    "@angular/core": "2.0.0-rc.4",
    "@angular/forms": "^0.2.0",
    "@angular/http": "2.0.0-rc.4",
    "@angular/platform-browser": "2.0.0-rc.4",
    "@angular/platform-browser-dynamic": "2.0.0-rc.4",
    "@angular/router": "3.0.0-beta.1",
    "@angular/router-deprecated": "2.0.0-rc.2",
    "@angular/upgrade": "2.0.0-rc.4",

    "angular2-in-memory-web-api": "0.0.9",
    "core-js": "^2.4.0",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.6",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.12"
  }

Try running NPM from a command prompt, or go to Visual Studio output window and change “Show output from” to “bower/npm”. If you see errores complaining about a version not existing of some package, the message will tell you what versions are available, and then you can just pick the highest.

For example, I’m excluding replacing the deprecated router from this exercise. So I kept it, and it didn’t have a package for rc4. The error message about that told me that the max version available is rc2, and that seemed to work fine.

The new router also has its own version. You should be able to see that version in the config file like the other Angular files though.

Angular Forms

After that, since Angular forms became a separate module in RC3, this module was not included.

So, first you need to add it, it has a separate version as well. The plunker systemJS file will tell you what. And it’s shown in the above sample.

Then, you also need to add it into your own systemJS config file systemjs.config.js. Just add it to the packageNames definition. It should then look like:

var packageNames = [
    '@angular/common',
    '@angular/compiler',
    '@angular/core',
    '@angular/forms',
    '@angular/http',
    '@angular/platform-browser',
    '@angular/platform-browser-dynamic',
    '@angular/router',
    '@angular/router-deprecated',
    '@angular/testing',
    '@angular/upgrade',
];

And that’s it. Run the application again. You should still see the demo Todo-list with routing working.

Look at the browser devtools console. You should see a warning that you are using the deprecated forms module (what is available by default), and shows you a link of how to override it.

This means the project is working well with Angular 2 RC4, and the deprecated forms and router.

Cleanup

Next, you should be able to start deleting the sample components to leave for your own application components.

Before you do that, you might want to see how the project template works, including the serverside ASP.NET MVC bits. This will give you some guidance on how to structure your own.

Once you are done, you can remove the deprecated router from application bootstrapping file and from NPM dependencies. Then start using the new router, which we already included in the previous steps.

You should also be good to disable the deprecated forms (those are not a separate NPM module, so that stays the same), by modifying the application bootstrapping code as the link in the browser console tells you.

Good luck :)

Angular 2 for Angular 1 Developers — Full Video of My DDD Sydney 2016 Talk

Whether you have been to my talk at DDD Sydney 2016, or we never met before, here’s the entire recording as I captured it on my machine.

I decided to just upload the raw file with minimum or no video editing, so that I can get it up as soon as possible.

Let me know what you think, and what you’d like me to talk about in future videos.

You can tweet at me — @Meligy, and I’ll reply back as soon as I see it.

How to use TypeScript Enum types, especially with Angular 2

Let’s assume you have the following enum in TypeScript:

export enum AgentStatus {
    available =1 ,
    busy = 2,
    away = 3,
    offline = 0
}

An enum is just an object. Your enum is written something like this in JavaScript:

{
    0: "offline",
    1: "available",
    2: "busy",
    3: "away",
    available: 1,
    busy: 2,
    away: 3,
    offline: 0
}

The benefit from typing is very limited in enums. Let me explain…

A very common thing you might want to do, is convert a string to an enum. This line is valid:

var value = <AgentStatus>"offline";

But it’s not useful, because

value == AgentStatus.offline // <- false, because it's "offline" == 0

So, you should always store your values as numbers, which you can obtain as follows:

How do you convert a string to an enum in TypeScript?

var value = AgentStatus["offline"]; // so value is now 0

// You can also use this, which only gives IDE hints, no runtime benefit
var value: AgentStatus = AgentStatus["offline"];

This makes the previous comparison work:

value == AgentStatus.offline // <- true, because it's 0 == 0

Now, a couple questions remain:

How to convert a TypeScript enum value to a string?

AgentStatus.offline // 0
AgentStatus[AgentStatus.offline] // -> AgentStatus[0] -> "offline"

How to get all the values of a TypeScript enum type?

var options : string[] = Object.keys(AgentStatus);
// The options list has the numeric keys, followed by the string keys
// So, the first half is numeric, the 2nd half is strings
options = options.slice(options.length / 2);

Gotcha: Undefined enum type in Angular 2 views

If you write this in your Angular2 template:

{{AgentStatus[myValue]}}

It will fail, because it doesn’t have access to imported types (it gets executed later by AngularJS).

To make it work, your component will need to have a reference to the enum type / object, something like:

export class MyComponent {
    // allows you to use AgentStatus in template
    AgentStatus = AgentStatus;        

    myValue : AgentStatus;
    // ...
}

Runnable Demo With All Solutions

Here is an example that explains everything I pointed in here:

(Click the button at the top right to see it in action)

This post was inspired by this StackOverflow answer.