Re: =[xhr]

2014-08-04 Thread nmork_consultant
I've seen that sort of code before.  Sometimes unforseen events occur 
leaving you with a nonworkable screen.  I tend to trust Javascript less 
than the environment on the server.  Yes, there are better ways to build a

DB application than web technology, but we are presented with the 
programming challenge of adding to a portion of  DB application to an 
existing intranet application and now need the tools that will make the 
browser behave very non-web for a few moments.  Can be a challenge.

I still don't understand how this request has become a harangue to make 
sure I know that everybody thinks I am wrong to make such a request.  I 
spoke about specific situations where I found synchronous xmlhttprequests 
to be useful and based on that, I expect them to be useful in the future. 
What I get back are very general vague assertions that seem to

1. Assume I never use asynchronous xmlhttprequests (not true, I use them 
predominantly)
2. Seem to ask me to take into account all situations, imagine all 
possibilities when I am only trying to solve 1 issue on 1 screen in 1 
application

My only assertion is: when synchronous xmlhttprequests are required, async

WILL NOT WORK and are not appropriate.  Simply repeating the mantra over 
and over is not convincing.



From:   David Bruant 
To: nmork_consult...@cusa.canon.com, 
Cc: Austin William Wright , Glenn Maynard 
, "Tab Atkins Jr." , public-webapps 

Date:   08/04/2014 08:07 AM
Subject:Re: =[xhr]



Le 04/08/2014 15:30, nmork_consult...@cusa.canon.com a écrit :
This is an intranet application.  The server is in the next room (locked, 
of course.) 
I was seeing this one coming when I wrote my paragraph :-p
If you're in a tightly controlled environment, one could question the 
choice of a web application, but that's beyond the point of this email.

However, many (not all) POST operations require only 1 channel to be 
active at a time, especially in intranet applications.
As someone else noted, how do you know two computers aren't connected at 
the same time? Or even that the same user isn't logged in in two different

machines within the network?
Note also that as others said, sync xhr doesn't freeze the browser, so if 
your application isn't robust to the user changing tab, or going back, you

may have a bug you want to fix.

If your answer resembles even vaguely "because I control the environment 
and want to prevent the user from doing x, y, z and will as long as I 
can", then, I'd like to question again whether you really want to make 
your intranet application run a web browser.
There are lots of other choices to make non-web applications, but the web 
platform took the path of prioritizing the end-user concerns above all 
else. See the "Priority of Constituencies" : 
http://www.w3.org/TR/html-design-principles/#priority-of-constituencies
We've had a foggy period at the beginning of the web, but it's clear now 
that end-users are considered as a priority in web standards and 
implementors (though obviously various parties will see end-user interests

from a different perspective).

If you care about how your software ensures some guarantees for your 
database above providing a good user experience, the web might not be 
where you want to make your application and I think that you will keep 
meeting resistance in web standards mailing-lists.

No user wants to be given the freedom to accidentally screw up. 
Why would you write code that provides that freedom, though?
In cases like you describe, I would send the POST request asynchronously 
and then disable any user interface that allows to send another request 
until the server comes back with a 200 (or equivalent) via either removing

the event listeners. In essence, that would look like:

var postUrl = '...';
postButton.addEventListener('click', function clickHandler(){
var xhr = new XMLHttpRequest();
xhr.open('POST', postUrl);
xhr.addEventListener('load', function(){
// POST came back, re-enable the button
postButton.removeEventListener('click', clickHandler);
postButton.setAttribute('disabled', 'disabled');
});
xhr.send();

// disable UI for POSTing
postButton.removeEventListener('click', clickHandler);
postButton.setAttribute('disabled', 'disabled');
// maybe add a spinner somewhere and/or invite the user
// to have a hot beverage of their choice as you suggested
});

Of course, disable any other UI element you need, error handling is 
missing, etc, but you get the idea.
The above code demonstrates that you can prevent the user from further 
interacting with the database, yet use async xhr.

David


Re: =[xhr]

2014-08-04 Thread nmork_consultant
True.



From:   "James M. Greene" 
To: nmork_consult...@cusa.canon.com, 
Cc: Austin William Wright , Glenn Maynard 
, "Tab Atkins Jr." , public-webapps 

Date:   08/04/2014 06:44 AM
Subject:Re: =[xhr]



HOWEVER, I am getting the distinct impression that even though I find 
synchronous xmlhttprequests extremely useful in some situations to prevend 
DB corruption--usually I avoid these situations, due to the negative 
impacts you have all described so well in your emails.

While I personally agree with you that synchronous XHRs have their rare 
but distinct uses, preventing DB corruption doesn't seem like a realistic 
one as the synchronicity of an XHR only affects the single client who is 
making the request.  If your intranet app has more than 1 client, you 
would still need to guarantee clean DB operation queuing on the backend.

Sincerely,
James Greene



On Mon, Aug 4, 2014 at 8:29 AM,  wrote:
You are acting as though I have to choose one or the other and stick with 
it.  Async has it's uses, especially for GET operations.  However, many 
(not all) POST operations require only 1 channel to be active at a time, 
especially in intranet applications.  No user wants to be given the 
freedom to accidentally screw up. 

The problem with recent developments in the web browser world, it seems 
that things that are useful are deprecated then disappear, even if useful 
for one purpose or another and that is my request.  There seems to be some 
confusion and everyone is acting as if I only wish to use synchronous 
xmlhttprequests.  If async were to be deprecated, I would complain as much 
as I am or more.   

HOWEVER, I am getting the distinct impression that even though I find 
synchronous xmlhttprequests extremely useful in some situations to prevend 
DB corruption--usually I avoid these situations, due to the negative 
impacts you have all described so well in your emails.  That said, there 
are times when it is the only option.  Everyone in your group seems to 
have taken the attitude that I am mistaken, confused, or stupid.  I am 
only requesting for synchronous xmlhttprequests NOT to be deprecated and 
NOT to be eliminated from the specification.  It's pretty clear to me now 
that my request will not be considered.  Thank you all for your responses. 




From:Austin William Wright  
To:Glenn Maynard , 
Cc:nmork_consult...@cusa.canon.com, "Tab Atkins Jr." <
jackalm...@gmail.com>, public-webapps  
Date:08/02/2014 02:11 AM 
Subject:Re: =[xhr] 




On Fri, Aug 1, 2014 at 2:01 PM, Glenn Maynard  wrote: 
On Fri, Aug 1, 2014 at 8:39 AM,  wrote: 
Spinner is not sufficient.  All user activity must stop.  They can take  a 
coffee break if it takes too long.  Browser must be frozen and locked down 
completely.  No other options are desirable.  All tabs, menus, etc. must 
be frozen.  That is exactly the desired result. 

My browser isn't yours to lock down.  My menus aren't yours to freeze. 
 You don't get to halt my browser, it doesn't belong to you. 

In this case, a freeze on all browser operations is desirable. 

It may be desirable to you, but it's never desirable to the user, and 
users come first. 


This seems rather cold (I wouldn't presume that the described usage is 
actually bad for the users, not having seen the program in question), 
though assertion is technically correct (if users are at odds with 
development of a technical report, users come first). I would point out: 

It may be cheap for the developer to use synchronous mode, but it's not 
the UI event loop works, and as such it's almost always a bad proposition 
for the user. It's not a sustainable coding pattern (what if you want to 
listen for two operations at the same time?), it's generally a hack all 
around. It doesn't negate the need for your application to perform sanity 
checks like "Is the data loaded? Does performing this operation make 
sense?", even if using synchronous mode *seems* to let you avoid such 
checks. 

Maybe there's another reason: Good idea or no, removing this feature DOES 
break reverse compatibility with the de-facto behavior of many Web 
browsers. I'm not sure that's reason enough to standardize on the 
behavior, though. However, it may be enough a reason to file a bug report 
if the behavior ever breaks (though if they come back and say "it was 
never standardized behavior to begin with, you shouldn't have been using 
it in production", I can't really blame that either). 

Austin Wright. 



Re: =[xhr]

2014-08-04 Thread nmork_consultant
GOTOs have their uses, as well.  Try to write hardware control code or 
even a decent operating system without one.  Abuse of GOTO by persons not 
aware of the pros/cons can be a nightmare, however, I haven't seen a GOTO 
in anyone's code since 1992 (I began programming DB applications in the 
ISAM era 1983 when GOTO's were quite common.)

At one point, I had access to Windows v2.1 code and found some very nasty 
GOTO logic everywhere (jumping out of  3rd-level nested switch case to a 
section of code in another case in the top-level switch.  Dang hard to 
follow the coding logic.)  An old mainframe guy (Unisys 1100) explained to

me the when and why to use GOTOs.  It is a very efficient branching 
directive at the compiled code level.



From:   David Bruant 
To: Austin William Wright , Glenn Maynard 
, 
Cc: nmork_consult...@cusa.canon.com, "Tab Atkins Jr." 
, public-webapps 
Date:   08/02/2014 03:41 AM
Subject:Re: =[xhr]



Le 02/08/2014 11:11, Austin William Wright a écrit :
> Maybe there's another reason: Good idea or no, removing this feature 
> DOES break reverse compatibility with the de-facto behavior of many 
> Web browsers.
Everyone who wants sync xhr to disappear is well-aware. That's the 
reason it hasn't been removed yet.

Just as a reminder, we live on Planet Earth where the distance between 
two computers who want to communicate with one another can be 20.000km. 
A signal at speed light takes 60ms. But our network isn't either at 
speed light nor in straight line, so the delay is easily multiplied by 
20 and that's very optimistic. And that's just the latency. Bandwidth 
considerations and data processing times aren't free.
On the other hand, we're human beings and notice 100ms delays and all 
evidence converge in the direction of saying that human beings are 
frustrated when they feel a delay, so making people wait is terrible. 
(interesting talk which discusses perceived performance at one point 
http://vimeo.com/71278954 )
Sync xhr forces a delay and there is no way around that, ergo, it's 
terrible.

I'm probably not old enough to accurately make this comparison, but 
blocking I/O looks like it's 2010-era GOTO. I heard when higher-level 
programming came around, some people were strong defenser of GOTO. Now, 
most people have moved to higher-level constructs.
I think the same fate is waiting for blocking I/O.

David



Re: =[xhr]

2014-08-04 Thread nmork_consultant
This is an intranet application.  The server is in the next room (locked, 
of course.)



From:   David Bruant 
To: Austin William Wright , Glenn Maynard 
, 
Cc: nmork_consult...@cusa.canon.com, "Tab Atkins Jr." 
, public-webapps 
Date:   08/02/2014 03:41 AM
Subject:Re: =[xhr]



Le 02/08/2014 11:11, Austin William Wright a écrit :
> Maybe there's another reason: Good idea or no, removing this feature 
> DOES break reverse compatibility with the de-facto behavior of many 
> Web browsers.
Everyone who wants sync xhr to disappear is well-aware. That's the 
reason it hasn't been removed yet.

Just as a reminder, we live on Planet Earth where the distance between 
two computers who want to communicate with one another can be 20.000km. 
A signal at speed light takes 60ms. But our network isn't either at 
speed light nor in straight line, so the delay is easily multiplied by 
20 and that's very optimistic. And that's just the latency. Bandwidth 
considerations and data processing times aren't free.
On the other hand, we're human beings and notice 100ms delays and all 
evidence converge in the direction of saying that human beings are 
frustrated when they feel a delay, so making people wait is terrible. 
(interesting talk which discusses perceived performance at one point 
http://vimeo.com/71278954 )
Sync xhr forces a delay and there is no way around that, ergo, it's 
terrible.

I'm probably not old enough to accurately make this comparison, but 
blocking I/O looks like it's 2010-era GOTO. I heard when higher-level 
programming came around, some people were strong defenser of GOTO. Now, 
most people have moved to higher-level constructs.
I think the same fate is waiting for blocking I/O.

David



Re: =[xhr]

2014-08-04 Thread nmork_consultant
You are acting as though I have to choose one or the other and stick with 
it.  Async has it's uses, especially for GET operations.  However, many 
(not all) POST operations require only 1 channel to be active at a time, 
especially in intranet applications.  No user wants to be given the 
freedom to accidentally screw up.

The problem with recent developments in the web browser world, it seems 
that things that are useful are deprecated then disappear, even if useful 
for one purpose or another and that is my request.  There seems to be some 
confusion and everyone is acting as if I only wish to use synchronous 
xmlhttprequests.  If async were to be deprecated, I would complain as much 
as I am or more. 

HOWEVER, I am getting the distinct impression that even though I find 
synchronous xmlhttprequests extremely useful in some situations to prevend 
DB corruption--usually I avoid these situations, due to the negative 
impacts you have all described so well in your emails.  That said, there 
are times when it is the only option.  Everyone in your group seems to 
have taken the attitude that I am mistaken, confused, or stupid.  I am 
only requesting for synchronous xmlhttprequests NOT to be deprecated and 
NOT to be eliminated from the specification.  It's pretty clear to me now 
that my request will not be considered.  Thank you all for your responses.



From:   Austin William Wright 
To: Glenn Maynard , 
Cc: nmork_consult...@cusa.canon.com, "Tab Atkins Jr." 
, public-webapps 
Date:   08/02/2014 02:11 AM
Subject:Re: =[xhr]




On Fri, Aug 1, 2014 at 2:01 PM, Glenn Maynard  wrote:
On Fri, Aug 1, 2014 at 8:39 AM,  wrote:
Spinner is not sufficient.  All user activity must stop.  They can take  a 
coffee break if it takes too long.  Browser must be frozen and locked down 
completely.  No other options are desirable.  All tabs, menus, etc. must 
be frozen.  That is exactly the desired result. 

My browser isn't yours to lock down.  My menus aren't yours to freeze. 
 You don't get to halt my browser, it doesn't belong to you.

In this case, a freeze on all browser operations is desirable.

It may be desirable to you, but it's never desirable to the user, and 
users come first.


This seems rather cold (I wouldn't presume that the described usage is 
actually bad for the users, not having seen the program in question), 
though assertion is technically correct (if users are at odds with 
development of a technical report, users come first). I would point out:

It may be cheap for the developer to use synchronous mode, but it's not 
the UI event loop works, and as such it's almost always a bad proposition 
for the user. It's not a sustainable coding pattern (what if you want to 
listen for two operations at the same time?), it's generally a hack all 
around. It doesn't negate the need for your application to perform sanity 
checks like "Is the data loaded? Does performing this operation make 
sense?", even if using synchronous mode *seems* to let you avoid such 
checks.

Maybe there's another reason: Good idea or no, removing this feature DOES 
break reverse compatibility with the de-facto behavior of many Web 
browsers. I'm not sure that's reason enough to standardize on the 
behavior, though. However, it may be enough a reason to file a bug report 
if the behavior ever breaks (though if they come back and say "it was 
never standardized behavior to begin with, you shouldn't have been using 
it in production", I can't really blame that either).

Austin Wright.


Re: =[xhr]

2014-08-01 Thread nmork_consultant
If you use your tab key, you will discover that you will need to disable 
all controls under your spinner to prevent user input completely.  Kind of 
a lot of work to get exactly the effect that sync requests do for you.

I find sync xmlhttprequests useful and you don't, it's clear.  But instead 
of recognizing this and doing something like saying "hm.  interesting, 
maybe there is a use for it," you have decided since you have no use for 
sync requests that no one should be using them.  I don't care to go 
through the effort of trying to write this application with async requests 
again, when I already have experienced the fact they don't give me the 
desired behavior.



From:   Brian Kardell 
To: nmork_consult...@cusa.canon.com, 
Cc: public-webapps@w3.org, "Tab Atkins Jr." 
Date:   08/01/2014 07:13 AM
Subject:Re: =[xhr]




On Aug 1, 2014 9:52 AM,  wrote:
>
> Thank you for letting me know my input is not desired. 
>
As Tab said, you can visually and functionally lock user input in your tab 
and even provide a progress meter. Nothing you suggest is difficult with a 
sync xhr and promises, and it's less hostile.  How is this unreasonable?
>
> From:"Tab Atkins Jr."  
> To:nmork_consult...@cusa.canon.com, 
> Cc:public-webapps  
> Date:08/01/2014 06:46 AM 
> Subject:Re: =[xhr] 
> 
>
>
>
>
> On Aug 1, 2014 8:39 AM,  wrote:
> >
> > Spinner is not sufficient.  All user activity must stop.  They can 
take  a coffee break if it takes too long.  Browser must be frozen and 
locked down completely.  No other options are desirable.  All tabs, menus, 
etc. must be frozen.  That is exactly the desired result.
>
> By "spinner", I also meant freezing other parts of the page as 
necessary, or obscuring them so they can't be clicked.
>
> Asking to freeze the rest of the browser is unnecessary and extremely 
user-hostile, and we don't support allowing content to do that.
>
> ~TJ


Re: =[xhr]

2014-08-01 Thread nmork_consultant
Thank you for letting me know my input is not desired.



From:   "Tab Atkins Jr." 
To: nmork_consult...@cusa.canon.com, 
Cc: public-webapps 
Date:   08/01/2014 06:46 AM
Subject:Re: =[xhr]




On Aug 1, 2014 8:39 AM,  wrote:
>
> Spinner is not sufficient.  All user activity must stop.  They can take 
 a coffee break if it takes too long.  Browser must be frozen and locked 
down completely.  No other options are desirable.  All tabs, menus, etc. 
must be frozen.  That is exactly the desired result. 
By "spinner", I also meant freezing other parts of the page as necessary, 
or obscuring them so they can't be clicked.
Asking to freeze the rest of the browser is unnecessary and extremely 
user-hostile, and we don't support allowing content to do that.
~TJ


Re: =[xhr]

2014-08-01 Thread nmork_consultant
Spinner is not sufficient.  All user activity must stop.  They can take  a 
coffee break if it takes too long.  Browser must be frozen and locked down 
completely.  No other options are desirable.  All tabs, menus, etc. must 
be frozen.  That is exactly the desired result.



From:   "Tab Atkins Jr." 
To: nmork_consult...@cusa.canon.com, 
Cc: public-webapps 
Date:   08/01/2014 06:33 AM
Subject:Re: =[xhr]




On Aug 1, 2014 8:16 AM,  wrote:
>
> In this case, a freeze on all browser operations is desirable.  The 
thread cannot be interrupted, and if it is interrupted (by browser closure 
or other such) then the transactions are immediately stopped and no update 
will occur (this is the most desirable outcome.)  
Assuming you're handling transactions yourself, using async XHR has no 
effect on this. (The browser doesn't provide any transactions for you.)
Async XHR doesn't continue after tab closure.
> Async is not desirable, since it gives control back to the browser and 
the user has a false impression that interaction may be ok or even 
desirable.  In this case it is not, it is an all stop until complete 
requirement.  
You can throw up a spinner to indicate that if you want, and get the same 
effect. The spinner solution lets you do more things, too, such as 
providing feedback or other information to the user. (Or just allowing 
hover effects to work - freezing the main thread restricts a *lot* of 
things.)
> I use both async and sync xmlhttprequests, and they both have their 
place.  Please do not deprecate sync requests simply because you cannot 
imagine where they would be desirable.  When they are needed, they are 
ABSOLUTELY needed and async requests are not only NOT desirable, but can 
lead to potentially disastrous results. 
Sync XHR offers you literally nothing over async XHR besides a little bit 
of restrictive simplicity. There is absolutely no situation in which sync 
XHR is actually required.
~TJ


Re: =[xhr]

2014-08-01 Thread nmork_consultant
In this case, a freeze on all browser operations is desirable.  The thread 
cannot be interrupted, and if it is interrupted (by browser closure or 
other such) then the transactions are immediately stopped and no update 
will occur (this is the most desirable outcome.)  Async is not desirable, 
since it gives control back to the browser and the user has a false 
impression that interaction may be ok or even desirable.  In this case it 
is not, it is an all stop until complete requirement.  I use both async 
and sync xmlhttprequests, and they both have their place.  Please do not 
deprecate sync requests simply because you cannot imagine where they would 
be desirable.  When they are needed, they are ABSOLUTELY needed and async 
requests are not only NOT desirable, but can lead to potentially 
disastrous results.



From:   "Tab Atkins Jr." 
To: nmork_consult...@cusa.canon.com, 
Cc: public-webapps 
Date:   07/31/2014 03:47 PM
Subject:Re: =[xhr]



On Tue, Jul 29, 2014 at 1:41 PM,   wrote:
> While debugging an intranet application using xmlHttpRequest recently, I 
got
> a message on the Firefox browser console: "Synchronous XMLHttpRequest on 
the
> main thread is deprecated because of its detrimental effects to the end
> user's experience."
>
> This worries me, since many useful web browser features which are
> "deprecated" eventually disappear (e.g. CSS width specification in the 

> tag.)

This is definitely one of those things.

>  I have an application which makes many http requests to make multiple
> large updates to database work tables, finally running a single SQL
> xmlHttpRequest to copy all work table data to the main data tables after 
all
> updates are successful.
>
> 1. The volume and size of the data is too large to be sent by a single
> request
> 2. Each subsequent request cannot be submitted until the prior request 
is
> completed SUCCESSFULLY or the database will be corrupted
> 3. The final SQL acts as the "commit" for the whole shebang and has its 
own
> BEGIN TRANSACTION and COMMIT/ROLLBACK for safety
>
> In this case, synchronous xmlHttpRequests are not only NOT deprecated, 
they
> are ABSOLUTELY ESSENTIAL to provide reliable database updating for the 
end
> user, and reliability is what the end user most desires, in addition to
> IMMEDIATE FEEDBACK whether the update succeeded or not.

None of what you have described requires a synchronous XHR; it can all
be done with async XHR.  You just wait to send the subsequent batches
of data until the listener from the previous one informs you that it
has succeeded.  This is slightly more complicated than doing sync, but
no slower (and possible faster, if some of them can be done in
parallel), and just as reliable.

You get feedback exactly as quickly, modulo a millisecond or two of
accumulated delay from waiting for your listener to reach the top of
the message queue.

Your users get a vastly better experience out of it, too.  Synchronous
XHR freezes the JS main thread until it returns, which means that any
interaction with the page is frozen too.  (Users *might* be able to
scroll, if the browser is doing scrolling on another thread, but
that's about it.)  Multiple large consecutive sync XHRs mean things
are frozen for a noticeable amount of time, especially if the network
is slow for whatever reason.  Async XHR has none of this problem.

The last person on this list to assert that they absolutely needed
sync XHR didn't seem to understand what async XHR was.  (They seemed
to think it was related to form submission; I don't know what you
think it is.)  It's exactly identical to sync XHR, but rather than
freezing javascript until the response comes back, and giving you the
result as a return value, you just have to register an event listener
which'll get called when the response comes back, passing the result
as an argument to your callback.  Spreading your logic across
callbacks is a little bit more complicated than doing sync code, but
it's a necessary part of tons of JS APIs already, so if you're not
familiar with how it works, you're gonna have to get familiar with it
really soon. ^_^

> Also, unrelated, please bring back CSS width to the  tag.  On very
> large data tables, this can reduce page downloads by megabytes, no 
matter
> how small you make your column class names.

Rather than putting classes on your s, you can just use better
selectors.  If you need to set the width of the cells in the second
column, you can just do `td:nth-child(2) { width: XXX; }`.  Save
yourself a couple megabytes. ^_^

(This isn't *precisely* reliable, because it doesn't know about
rowspans/colspans, but you can often deal with that yourself.
Selectors level 4 adds an :nth-column() pseudo-class which is
identical to :nth-child(), but only works on table cells and knows
about rowspans and colspans, so it'll properly style everything in the
desired column no matter how the table is structured.)

~TJ



=[xhr]

2014-07-31 Thread nmork_consultant
While debugging an intranet application using xmlHttpRequest recently, I 
got a message on the Firefox browser console: "Synchronous XMLHttpRequest 
on the main thread is deprecated because of its detrimental effects to the 
end user's experience."

This worries me, since many useful web browser features which are 
"deprecated" eventually disappear (e.g. CSS width specification in the 
 tag.)  I have an application which makes many http requests to make 
multiple large updates to database work tables, finally running a single 
SQL xmlHttpRequest to copy all work table data to the main data tables 
after all updates are successful.

1. The volume and size of the data is too large to be sent by a single 
request
2. Each subsequent request cannot be submitted until the prior request is 
completed SUCCESSFULLY or the database will be corrupted
3. The final SQL acts as the "commit" for the whole shebang and has its 
own BEGIN TRANSACTION and COMMIT/ROLLBACK for safety

In this case, synchronous xmlHttpRequests are not only NOT deprecated, 
they are ABSOLUTELY ESSENTIAL to provide reliable database updating for 
the end user, and reliability is what the end user most desires, in 
addition to IMMEDIATE FEEDBACK whether the update succeeded or not.

Please do not deprecate synchronous xmlHttpRequests.  They are needed in 
general and specifically needed for complex web applications.

Also, unrelated, please bring back CSS width to the  tag.  On very 
large data tables, this can reduce page downloads by megabytes, no matter 
how small you make your column class names.