Changeset 139009 in webkit


Ignore:
Timestamp:
Jan 7, 2013, 4:20:54 PM (12 years ago)
Author:
ap@apple.com
Message:

[WK2] Make SecItemShim messages work with any process
https://bugs.webkit.org/show_bug.cgi?id=106269

Reviewed by Sam Weinig.

Add SecItemShim and SecItemShimProxy classes to manage message sending, and moved
relevant code from WebProcess(Proxy).

  • DerivedSources.make:
  • Platform/CoreIPC/MessageID.h:
  • UIProcess/WebProcessProxy.cpp: (WebKit::WebProcessProxy::didFinishLaunching):
  • UIProcess/WebProcessProxy.h: (WebProcessProxy):
  • UIProcess/WebProcessProxy.messages.in:
  • Shared/mac/SecItemShim.cpp: Added. (WebKit::SecItemShim::shared): (WebKit::SecItemShim::SecItemShim): (WebKit::SecItemShim::secItemResponse): (WebKit::SecItemShim::install): (WebKit::SecItemShim::didReceiveMessageOnConnectionWorkQueue):
  • Shared/mac/SecItemShim.h: Added.
  • Shared/mac/SecItemShim.messages.in: Added.
  • UIProcess/mac/SecItemShimProxy.cpp: Added. (WebKit::SecItemShimProxy::shared): (WebKit::SecItemShimProxy::SecItemShimProxy): (WebKit::handleSecItemRequest): (WebKit::dispatchFunctionOnQueue): (WebKit::SecItemShimProxy::secItemRequest): (WebKit::SecItemShimProxy::didReceiveMessageOnConnectionWorkQueue):
  • UIProcess/mac/SecItemShimProxy.h: Added.
  • UIProcess/mac/SecItemShimProxy.messages.in: Added.
  • UIProcess/mac/WebProcessProxyMac.mm:
  • WebKit2.xcodeproj/project.pbxproj:
  • WebProcess/WebProcess.cpp: (WebKit::WebProcess::initializeConnection):
  • WebProcess/WebProcess.h:
  • WebProcess/WebProcess.messages.in:
  • WebProcess/mac/SecItemShimMethods.mm: (WebKit::sendSeqItemRequest):
  • WebProcess/mac/WebProcessMac.mm: (WebKit::WebProcess::platformInitializeProcess):
Location:
trunk/Source/WebKit2
Files:
6 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r139003 r139009  
     12013-01-07  Alexey Proskuryakov  <ap@apple.com>
     2
     3        [WK2] Make SecItemShim messages work with any process
     4        https://bugs.webkit.org/show_bug.cgi?id=106269
     5
     6        Reviewed by Sam Weinig.
     7
     8        Add SecItemShim and SecItemShimProxy classes to manage message sending, and moved
     9        relevant code from WebProcess(Proxy).
     10
     11        * DerivedSources.make:
     12        * Platform/CoreIPC/MessageID.h:
     13        * UIProcess/WebProcessProxy.cpp:
     14        (WebKit::WebProcessProxy::didFinishLaunching):
     15        * UIProcess/WebProcessProxy.h:
     16        (WebProcessProxy):
     17        * UIProcess/WebProcessProxy.messages.in:
     18        * Shared/mac/SecItemShim.cpp: Added.
     19        (WebKit::SecItemShim::shared):
     20        (WebKit::SecItemShim::SecItemShim):
     21        (WebKit::SecItemShim::secItemResponse):
     22        (WebKit::SecItemShim::install):
     23        (WebKit::SecItemShim::didReceiveMessageOnConnectionWorkQueue):
     24        * Shared/mac/SecItemShim.h: Added.
     25        * Shared/mac/SecItemShim.messages.in: Added.
     26        * UIProcess/mac/SecItemShimProxy.cpp: Added.
     27        (WebKit::SecItemShimProxy::shared):
     28        (WebKit::SecItemShimProxy::SecItemShimProxy):
     29        (WebKit::handleSecItemRequest):
     30        (WebKit::dispatchFunctionOnQueue):
     31        (WebKit::SecItemShimProxy::secItemRequest):
     32        (WebKit::SecItemShimProxy::didReceiveMessageOnConnectionWorkQueue):
     33        * UIProcess/mac/SecItemShimProxy.h: Added.
     34        * UIProcess/mac/SecItemShimProxy.messages.in: Added.
     35        * UIProcess/mac/WebProcessProxyMac.mm:
     36        * WebKit2.xcodeproj/project.pbxproj:
     37        * WebProcess/WebProcess.cpp:
     38        (WebKit::WebProcess::initializeConnection):
     39        * WebProcess/WebProcess.h:
     40        * WebProcess/WebProcess.messages.in:
     41        * WebProcess/mac/SecItemShimMethods.mm:
     42        (WebKit::sendSeqItemRequest):
     43        * WebProcess/mac/WebProcessMac.mm:
     44        (WebKit::WebProcess::platformInitializeProcess):
     45
    1462013-01-07  Anders Carlsson  <andersca@apple.com>
    247
  • trunk/Source/WebKit2/DerivedSources.make

    r137806 r139009  
    2828    $(WebKit2)/Shared/Plugins \
    2929    $(WebKit2)/Shared \
     30    $(WebKit2)/Shared/mac \
    3031    $(WebKit2)/Shared/Network/CustomProtocols \
    3132    $(WebKit2)/SharedWorkerProcess \
     
    8283    NetworkResourceLoader \
    8384    RemoteLayerTreeHost \
     85    SecItemShim \
     86    SecItemShimProxy \
    8487    WebContext \
    8588    WebDatabaseManager \
  • trunk/Source/WebKit2/Platform/CoreIPC/MessageID.h

    r137358 r139009  
    137137    MessageClassCustomProtocolManagerProxy,
    138138#endif
     139
     140#if USE(SECURITY_FRAMEWORK)
     141    // Messages sent by a web process or a network process to the UI process.
     142    MessageClassSecItemShimProxy,
     143
     144    // Responses to SecItemShimProxy that are sent back.
     145    MessageClassSecItemShim,
     146#endif
    139147};
    140148
  • trunk/Source/WebKit2/UIProcess/WebProcessProxy.cpp

    r137831 r139009  
    5454#endif
    5555
     56#if USE(SECURITY_FRAMEWORK)
     57#include "SecItemShimProxy.h"
     58#endif
     59
    5660using namespace WebCore;
    5761using namespace std;
     
    503507    ChildProcessProxy::didFinishLaunching(launcher, connectionIdentifier);
    504508
     509#if USE(SECURITY_FRAMEWORK)
     510    connection()->addQueueClient(&SecItemShimProxy::shared());
     511#endif
     512
    505513    m_webConnection = WebConnectionToWebProcess::create(this);
    506514
  • trunk/Source/WebKit2/UIProcess/WebProcessProxy.h

    r137813 r139009  
    5252namespace WebKit {
    5353
    54 #if USE(SECURITY_FRAMEWORK)
    55 class SecItemRequestData;
    56 class SecItemResponseData;
    57 #endif
    58 
    5954class DownloadProxyMap;
    6055class WebBackForwardListItem;
     
    154149#endif
    155150
    156 #if USE(SECURITY_FRAMEWORK)
    157     void secItemRequest(CoreIPC::Connection*, uint64_t requestID, const SecItemRequestData&);
    158 #endif
    159 
    160151    // CoreIPC::Connection::Client
    161152    friend class WebConnectionToWebProcess;
  • trunk/Source/WebKit2/UIProcess/WebProcessProxy.messages.in

    r136612 r139009  
    5353#endif
    5454
    55 #if USE(SECURITY_FRAMEWORK)
    56     SecItemRequest(uint64_t requestID, WebKit::SecItemRequestData request) DispatchOnConnectionQueue
    57 #endif
    58 
    5955}
  • trunk/Source/WebKit2/UIProcess/mac/WebProcessProxyMac.mm

    r138982 r139009  
    2727#import "WebProcessProxy.h"
    2828
    29 #import "SecItemRequestData.h"
    30 #import "SecItemResponseData.h"
    3129#import "WebProcessMessages.h"
    3230#import "WKFullKeyboardAccessWatcher.h"
    33 #import <Security/SecItem.h>
    3431
    3532namespace WebKit {
    36 
    37 static void handleSecItemRequest(CoreIPC::Connection* connection, uint64_t requestID, const SecItemRequestData& request)
    38 {
    39     SecItemResponseData response;
    40 
    41     switch (request.type()) {
    42         case SecItemRequestData::Invalid:
    43             ASSERT_NOT_REACHED();
    44             return;
    45 
    46         case SecItemRequestData::CopyMatching: {
    47             CFTypeRef resultObject = 0;
    48             OSStatus resultCode = SecItemCopyMatching(request.query(), &resultObject);
    49             response = SecItemResponseData(resultCode, adoptCF(resultObject).get());
    50             break;
    51         }
    52 
    53         case SecItemRequestData::Add: {
    54             CFTypeRef resultObject = 0;
    55             OSStatus resultCode = SecItemAdd(request.query(), &resultObject);
    56             response = SecItemResponseData(resultCode, adoptCF(resultObject).get());
    57             break;
    58         }
    59 
    60         case SecItemRequestData::Update: {
    61             OSStatus resultCode = SecItemUpdate(request.query(), request.attributesToMatch());
    62             response = SecItemResponseData(resultCode, 0);
    63             break;
    64         }
    65 
    66         case SecItemRequestData::Delete: {
    67             OSStatus resultCode = SecItemDelete(request.query());
    68             response = SecItemResponseData(resultCode, 0);
    69             break;
    70         }
    71     }
    72 
    73     connection->send(Messages::WebProcess::SecItemResponse(requestID, response), 0);
    74 }
    75 
    76 static void dispatchFunctionOnQueue(dispatch_queue_t queue, const Function<void ()>& function)
    77 {
    78 #if COMPILER(CLANG)
    79     dispatch_async(queue, function);
    80 #else
    81     Function<void ()>* functionPtr = new Function<void ()>(function);
    82     dispatch_async(queue, ^{
    83         (*functionPtr)();
    84         delete functionPtr;
    85     });
    86 #endif
    87 }
    88 
    89 void WebProcessProxy::secItemRequest(CoreIPC::Connection* connection, uint64_t requestID, const SecItemRequestData& request)
    90 {
    91     // Since we don't want the connection work queue to be held up, we do all
    92     // keychain interaction work on a global dispatch queue.
    93     dispatch_queue_t keychainWorkQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    94     dispatchFunctionOnQueue(keychainWorkQueue, bind(handleSecItemRequest, RefPtr<CoreIPC::Connection>(connection), requestID, request));
    95 }
    9633
    9734bool WebProcessProxy::fullKeyboardAccessEnabled()
  • trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj

    r138981 r139009  
    10361036                E17BF99814D0AA8300A5A069 /* NetscapeSandboxFunctions.mm in Sources */ = {isa = PBXBuildFile; fileRef = E17BF99714D0AA8300A5A069 /* NetscapeSandboxFunctions.mm */; };
    10371037                E18C92F412DB9E7100CF2AEB /* PrintInfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18C92F312DB9E7100CF2AEB /* PrintInfo.cpp */; };
     1038                E18E690B169B563F009B6670 /* SecItemShimProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E6909169B563F009B6670 /* SecItemShimProxy.cpp */; };
     1039                E18E690C169B563F009B6670 /* SecItemShimProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = E18E690A169B563F009B6670 /* SecItemShimProxy.h */; };
     1040                E18E6915169B667B009B6670 /* SecItemShimMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E6911169B667B009B6670 /* SecItemShimMessageReceiver.cpp */; };
     1041                E18E6916169B667B009B6670 /* SecItemShimMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = E18E6912169B667B009B6670 /* SecItemShimMessages.h */; };
     1042                E18E6917169B667B009B6670 /* SecItemShimProxyMessageReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E6913169B667B009B6670 /* SecItemShimProxyMessageReceiver.cpp */; };
     1043                E18E6918169B667B009B6670 /* SecItemShimProxyMessages.h in Headers */ = {isa = PBXBuildFile; fileRef = E18E6914169B667B009B6670 /* SecItemShimProxyMessages.h */; };
     1044                E18E6949169B77C8009B6670 /* SecItemShim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E18E6947169B77C8009B6670 /* SecItemShim.cpp */; };
     1045                E18E694A169B77C8009B6670 /* SecItemShim.h in Headers */ = {isa = PBXBuildFile; fileRef = E18E6948169B77C8009B6670 /* SecItemShim.h */; };
    10381046                E19582D3153CBFD700B60875 /* PDFKitImports.h in Headers */ = {isa = PBXBuildFile; fileRef = E19582D2153CBFD700B60875 /* PDFKitImports.h */; };
    10391047                E19582D6153CC05400B60875 /* PDFKitImports.mm in Sources */ = {isa = PBXBuildFile; fileRef = E19582D4153CC05300B60875 /* PDFKitImports.mm */; };
     
    23402348                E17BF99914D0CBF100A5A069 /* com.apple.WebKit.PluginProcess.sb.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = com.apple.WebKit.PluginProcess.sb.in; sourceTree = "<group>"; };
    23412349                E18C92F312DB9E7100CF2AEB /* PrintInfo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PrintInfo.cpp; sourceTree = "<group>"; };
     2350                E18E6909169B563F009B6670 /* SecItemShimProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecItemShimProxy.cpp; sourceTree = "<group>"; };
     2351                E18E690A169B563F009B6670 /* SecItemShimProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemShimProxy.h; sourceTree = "<group>"; };
     2352                E18E690D169B57DF009B6670 /* SecItemShimProxy.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SecItemShimProxy.messages.in; sourceTree = "<group>"; };
     2353                E18E690F169B5928009B6670 /* SecItemShim.messages.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SecItemShim.messages.in; sourceTree = "<group>"; };
     2354                E18E6911169B667B009B6670 /* SecItemShimMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecItemShimMessageReceiver.cpp; sourceTree = "<group>"; };
     2355                E18E6912169B667B009B6670 /* SecItemShimMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemShimMessages.h; sourceTree = "<group>"; };
     2356                E18E6913169B667B009B6670 /* SecItemShimProxyMessageReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecItemShimProxyMessageReceiver.cpp; sourceTree = "<group>"; };
     2357                E18E6914169B667B009B6670 /* SecItemShimProxyMessages.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemShimProxyMessages.h; sourceTree = "<group>"; };
     2358                E18E6947169B77C8009B6670 /* SecItemShim.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SecItemShim.cpp; sourceTree = "<group>"; };
     2359                E18E6948169B77C8009B6670 /* SecItemShim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SecItemShim.h; sourceTree = "<group>"; };
    23422360                E19582D2153CBFD700B60875 /* PDFKitImports.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PDFKitImports.h; sourceTree = "<group>"; };
    23432361                E19582D4153CC05300B60875 /* PDFKitImports.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PDFKitImports.mm; sourceTree = "<group>"; };
     
    38363854                                51D130511382EAC000351EDD /* SecItemResponseData.cpp */,
    38373855                                51D130521382EAC000351EDD /* SecItemResponseData.h */,
     3856                                E18E690F169B5928009B6670 /* SecItemShim.messages.in */,
     3857                                E18E6947169B77C8009B6670 /* SecItemShim.cpp */,
     3858                                E18E6948169B77C8009B6670 /* SecItemShim.h */,
    38383859                                BCE23262122C6CF300D5C35A /* WebCoreArgumentCodersMac.mm */,
    38393860                                BC111B5B112F629800337BAB /* WebEventFactory.h */,
     
    41404161                                1AA3D75D1651B5C5008713D0 /* RemoteLayerTreeHost.messages.in */,
    41414162                                1AA3D7591651B44F008713D0 /* RemoteLayerTreeHost.mm */,
     4163                                E18E690D169B57DF009B6670 /* SecItemShimProxy.messages.in */,
     4164                                E18E6909169B563F009B6670 /* SecItemShimProxy.cpp */,
     4165                                E18E690A169B563F009B6670 /* SecItemShimProxy.h */,
    41424166                                1AA417ED12C00D87002BE67B /* TextCheckerMac.mm */,
    41434167                                1AF05D8514688348008B1E81 /* TiledCoreAnimationDrawingAreaProxy.h */,
     
    43164340                                1AA3D75F1651B7D3008713D0 /* RemoteLayerTreeHostMessageReceiver.cpp */,
    43174341                                1AA3D7601651B7D3008713D0 /* RemoteLayerTreeHostMessages.h */,
     4342                                E18E6911169B667B009B6670 /* SecItemShimMessageReceiver.cpp */,
     4343                                E18E6912169B667B009B6670 /* SecItemShimMessages.h */,
     4344                                E18E6913169B667B009B6670 /* SecItemShimProxyMessageReceiver.cpp */,
     4345                                E18E6914169B667B009B6670 /* SecItemShimProxyMessages.h */,
    43184346                                E1EDFDB11628AD730039ECDA /* SharedWorkerProcessMessageReceiver.cpp */,
    43194347                                E1EDFDB21628AD730039ECDA /* SharedWorkerProcessMessages.h */,
     
    50395067                                BCF4DE25168FA44800C94AFC /* WebContextSupplement.h in Headers */,
    50405068                                BC9BA5051697C45300E44616 /* WebKit2Initialize.h in Headers */,
     5069                                E18E690C169B563F009B6670 /* SecItemShimProxy.h in Headers */,
     5070                                E18E6916169B667B009B6670 /* SecItemShimMessages.h in Headers */,
     5071                                E18E6918169B667B009B6670 /* SecItemShimProxyMessages.h in Headers */,
    50415072                                BC9BA50916991C3C00E44616 /* ChildProcessMain.h in Headers */,
     5073                                E18E694A169B77C8009B6670 /* SecItemShim.h in Headers */,
    50425074                        );
    50435075                        runOnlyForDeploymentPostprocessing = 0;
     
    60146046                                31A505F91680025500A930EB /* WebContextClient.cpp in Sources */,
    60156047                                BC9BA5041697C45300E44616 /* WebKit2Initialize.cpp in Sources */,
     6048                                E18E690B169B563F009B6670 /* SecItemShimProxy.cpp in Sources */,
     6049                                E18E6915169B667B009B6670 /* SecItemShimMessageReceiver.cpp in Sources */,
     6050                                E18E6917169B667B009B6670 /* SecItemShimProxyMessageReceiver.cpp in Sources */,
    60166051                                BC9BA50816991C3C00E44616 /* ChildProcessMain.mm in Sources */,
     6052                                E18E6949169B77C8009B6670 /* SecItemShim.cpp in Sources */,
    60176053                        );
    60186054                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/Source/WebKit2/WebProcess/WebProcess.cpp

    r138913 r139009  
    121121#endif
    122122
     123#if USE(SECURITY_FRAMEWORK)
     124#include "SecItemShim.h"
     125#endif
     126
    123127using namespace JSC;
    124128using namespace WebCore;
     
    208212    connection->addQueueClient(&m_eventDispatcher);
    209213    connection->addQueueClient(this);
     214
     215#if USE(SECURITY_FRAMEWORK)
     216    connection->addQueueClient(&SecItemShim::shared());
     217#endif
    210218
    211219    m_webConnection = WebConnectionToUIProcess::create(this);
  • trunk/Source/WebKit2/WebProcess/WebProcess.h

    r138913 r139009  
    9393#endif
    9494
    95 #if USE(SECURITY_FRAMEWORK)
    96 class SecItemResponseData;
    97 #endif
    98 
    9995#if ENABLE(NETWORK_PROCESS)
    10096class WebResourceLoadScheduler;
     
    271267    void postInjectedBundleMessage(const CoreIPC::DataReference& messageData);
    272268
    273 #if USE(SECURITY_FRAMEWORK)
    274     void secItemResponse(CoreIPC::Connection*, uint64_t requestID, const SecItemResponseData&);
    275 #endif
    276 
    277269    // ChildProcess
    278270    virtual void initializeProcess(const ChildProcessInitializationParameters&) OVERRIDE;
  • trunk/Source/WebKit2/WebProcess/WebProcess.messages.in

    r138729 r139009  
    9999    PostInjectedBundleMessage(CoreIPC::DataReference messageData);
    100100
    101 #if USE(SECURITY_FRAMEWORK)
    102     SecItemResponse(uint64_t requestID, WebKit::SecItemResponseData response) DispatchOnConnectionQueue
    103 #endif
    104 
    105101#if PLATFORM(MAC)
    106102    SetApplicationIsOccluded(bool flag);
  • trunk/Source/WebKit2/WebProcess/mac/SecItemShimMethods.mm

    r136620 r139009  
    3131#import "SecItemResponseData.h"
    3232#import "WebProcess.h"
    33 #import "WebProcessProxyMessages.h"
     33#import "SecItemShimProxyMessages.h"
    3434#import "WebProcessShim.h"
    3535#import <Security/SecItem.h>
     
    5858{
    5959    uint64_t requestID = generateSecItemRequestID();
    60     if (!WebProcess::shared().connection()->send(Messages::WebProcessProxy::SecItemRequest(requestID, SecItemRequestData(requestType, query, attributesToMatch)), 0))
     60    if (!WebProcess::shared().connection()->send(Messages::SecItemShimProxy::SecItemRequest(requestID, SecItemRequestData(requestType, query, attributesToMatch)), 0))
    6161        return nullptr;
    6262
  • trunk/Source/WebKit2/WebProcess/mac/WebProcessMac.mm

    r138913 r139009  
    2929#import "CustomProtocolManager.h"
    3030#import "SandboxExtension.h"
    31 #import "SecItemShimMethods.h"
    3231#import "WKFullKeyboardAccessWatcher.h"
    3332#import "WebInspector.h"
     
    4948#import <stdio.h>
    5049
     50#if USE(SECURITY_FRAMEWORK)
     51#import "SecItemShim.h"
     52#endif
     53
    5154#if ENABLE(WEB_PROCESS_SANDBOX)
    5255#import <pwd.h>
     
    309312{
    310313    WKAXRegisterRemoteApp();
    311     initializeSecItemShim();
     314
     315#if USE(SECURITY_FRAMEWORK)
     316    SecItemShim::shared().install();
     317#endif
    312318}
    313319
     
    321327}
    322328
    323 void WebProcess::secItemResponse(CoreIPC::Connection*, uint64_t requestID, const SecItemResponseData& response)
    324 {
    325     didReceiveSecItemResponse(requestID, response);
    326 }
    327 
    328329} // namespace WebKit
Note: See TracChangeset for help on using the changeset viewer.