Microsoft .NET PET SHOP 3.x: .NET PET SHOP design mode and architecture

xiaoxiao2021-03-06  83

Summary

Originally studied. The purpose of Net PET SHOP is to use Microsoft .NET to implement Sun's main J2EE Blueprint Application Sun Java PET Store the same application feature. Based on the SUN J2EE best practice sample application implemented by .NET, customers can directly compare Microsoft's .NET technology with J2EE-based application servers, and understand the use of web-based applications. Similarities and differences between various suggested design patterns. The .NET PET SHOP application is now a third edition, a .NET best practices designed to build an enterprise-level N-layer application (may need to support multiple database platforms and deploy models). According to the community's feedback on .NET PET SHOP 2.0, .NET PET SHOP 3.0 is redesigned in accordance with Microsoft "Descriptive Architecture Guide" issued on MSDN. The third edition also fully complies with the MiddleWare's application server benchmark specification, which will serve as Microsoft this spring's upcoming MiddleWare Application Server Benchmark: This is the second round of test activities held by Middleware, aiming to compare .NET And J2EE platforms are built and carrying scalability of enterprise web applications.

What is the Java Pet Store?

Java PET Store is a reference implementation of a distributed application developed by Sun's J2EE blueprint maintained by Sun. The original development purpose of the sample application is to help developers and architects understand how to use and utilize J2EE technology, and how each J2EE platform component works. The Java PET Store presentation software includes the Enterprise Java Beans (EJB) architecture required to build applications, Java Server Pages (JSP) technology, tag library and Servlet's complete source code and documentation. In addition, Java PET Store Blueprint applications also illustrate some models and design patterns through specific examples.

Complete Java PET Store consists of three sample applications:

• Java PET Store: J2EE Blueprumer application.

• Java Pet Store Manager: Manager module for Java Pet Store

• Blueprints MAiler: A small app for some J2EE Blueprint Design Guide in a small package.

The initial version of the Java PET Store is designed to process the following databases: Oracle, Sybase, and Cloudscape. IBM has developed a DB2 version of the application. The app is open from Java 2 Platform Enterprise Edition Blueprints. The primary application Java PET Store is an e-commerce application that can purchase pets online. Once the application starts the application, you can browse and search for all types of pets, from the dog to reptile.

A typical session scheme using the Java PET Store is as follows:

Home - This is the home page that the user loads when the application is first launched.

Category View - There are five categories: fish, dogs, reptiles, cats and birds. Every category has several related products. If you choose fish as a category, you can see the angel fish and so on.

Products - If you choose one product now, the application will display all types of products. Usually the product type is a male or female.

Product Details - Each product type (indicated by different items) has a detailed view showing product description, product image, price, and stock quantity.

Shopping Cart - users can operate shopping carts (add, delete, and update line items).

Checkout - Checkout page Show shopping cart with a read-only view.

Login Redirection - When the user selects "Continue" on the checkout page, if there is not yet logged in, it will be redirected to the login page. Login Verification - After the identity verification of the site, the user is redirected to the credit card and billing address form.

Order Confirmation - Displays the billing address and delivery address.

Fixed submission - this is the final step of the order processing process. The order will now be submitted to the database.

Microsoft .NET PET SHOP

The goal of .NET PET SHOP is to put the attention only on the Java PET Store (management and MAILER components are not implemented in .NET). In addition to reproducing the functions of the Java PET Store application, two goals have also increased:

• Compare .NET and J2EE Similarities and differences in the code and code size in real applications implemented through best practices.

• Provides a typical design of a typical design that is implemented with .NET and J2EE to support how many users' data.

The overall logical architecture of .NET PET SHOP is shown in Figure 3, the center of the design is in the representation layer using the ASP.NET web form, communicating with C # service components in the logical intermediate layer. Business components are successively used by ADO.NET and SQL Server named Data Access Application Block (which can learn more of more DAAB information and download the full DAAB source code) to access the backend database. Data Access Function is completely abstract into the Data Accepted Layer (DAL), separated from the service logic layer (BLL). The novel in .NET PET SHOP 3.0 is that we introduce the DAL layer for Oracle 9i and SQL Server 2000 databases. The class load of the corresponding DAL layer will be set to run during runtime according to the application configuration in Web.Config. Note .NET PET SHOP 3.0 uses two backend databases, and the distributed transactions across two databases are involved in the order processing. Using simple web.config application settings, users can deploy .NET PET Shop, use one or more backend databases, and freely use the SQL Server and Oracle backend database with components from the .NET service via COM . Distributed transaction mix of enterprise service processing.

Figure 3. .NET PET SHOP high-level logic architecture

Figure 4 illustrates how Microsoft .NET PET SHOP is physically deployed. Here, the network load balancing (NLB) or may be a hardware implemented load balancing technology, the inbound network traffic is divided into two application servers. When a network request reaches a machine in the cluster, all work for the request will be performed on this particular machine. Business Logic and Data Access Components will be installed on both servers in the form of an assembly, which is essentially identical. If the load balancing software is configured to use "Sticky IP", each server has its own session-status storage because the second request returns to the server that implements the first request. If the fault tolerance required for the solution is higher, two application servers can share a public session-status storage such as SQL Server or a dedicated session server (not shown). The type and location of the session-state storage is determined by the value of 'system.Web' element 'sessionState' subtition in each site 'Web.config' file.

Figure 4. Physical deployment diagram of .NET PET SHOP

Back to top

Business needs

As part of the PET SHOP 3 architecture, we give business needs of .NET PET SHOP, which developers and customers can understand some options we do when doing application design decisions.

What is the functional demand for PET SHOP applications?

• Applications should enable customers to browse company catalogs by category and via keyword search.

• Applications should provide customers with a mechanism for purchasing multiple commodity items through a shopping cart model.

• Applications should provide a simple security model so that customers must log in first, allowing the content of the shopping cart to be purchased. • Applications aim to support high-capacity enterprise-class e-commerce solutions; so applications should show the following:

• High performance, measure by the supported number and user response time

• Ability to expand by adding more processors

• By adding more machine to form a cluster distributed extension capability

• In large enterprise-class systems, applications may need to access multiple databases, so applications should support distributed transactions.

• Applications should consider a flexible deployment policy. By default, the application's design is to deploy on two machines. One is an application server, one is a database server, but it should be able to extend at other deployment models. Applications should support multiple database vendors. Here we chose Microsoft SQL Server and Oracle.

• Applications should be easy to maintain, which is measured by the number of lines in the application.

Application data model

The database architecture used in .NET PET SHOP is transplanted directly from Java Pet Store. The Java PET Store supports several database vendor formats, so we selected the Sybase application architecture and created in a Microsoft SQL Server 2000 instance. This does not need to change the Sybase version of the architecture. When you create an Oracle version. Net Pet Shop, we directly use the original Oracle implementation of the Java PET Store database.

The database has the following overall table structure, see Table 1:

Table 1. Database table in PET SHOP

Table Name

use

Account

Representing basic customer information

Bannerdata

Store advertising bar information

Category

Directory category (Fish, Dogs, Cats, etc.)

Inventory

Product inventory status

Item

Details of each product

LineItem

Order detail

ORDERS

The order under the customer. Order includes one or more rows

ORDERSTATUS

Order status

PRODUCT

Directory products, each product can have one or more types (items). Usually the type may be male or female.

Profile

Customer user configuration situation

Signon

Customer login table

Supplier

Supplier information

In .NET PET SHOP version 2, the application is changed to create a scheme, where the ordering process must be used to use a distributed transaction. In order to adapt to distributed transaction programs, the Orders, ORDERSTATUS, and LINEITEM tables are divided into database instances that may be installed on different machines. We maintain this distributed design pattern in the third edition of .NET PET SHOP.

Figure 5. .NET PET SHOP Ordering Database Architecture

Figure 6. .NET PET SHOP account and product database architecture

What can the design of the PET SHOP table do?

The architecture used in the application can do some changes; however, these changes are not consistent with the architectures provided with the Java Pet Store reference implementation. These changes are listed in Table 2:

Table 2. Possible improvements in the PET SHOP architecture

change

the reason

HTML is not stored in the table

Because you have to use different client applications, the database only stores image file names rather than image tags, deploying client types can be more flexible.

Use a single-way encryption algorithm for customer password

Help make the application more secure, because even if the security of any part of the system is threatened, the password is still difficult. This is a new value that requires facilities to reset the password.

Encrypting credit card information

Access to credit card information is prevented when system security is threatened. Other changes to make also set to only allow for writing access by a stored procedure; hacker access database will have to need another set of credentials to read data.

Back to top

.NET PET SHOP 2.0 Architecture Figure 7. Architecture of .NET PET SHOP 2 Application

.NET PET SHOP 2.0 is designed to deploy in a physically two-storey deployment environment, and this fact is used in some implementations of the application. The application consists of the following sections: a web layer created with an ASP.NET Web Form (with "code hide" Separate application HTML and user interface code). A business component containing control applications (accessing application blocks (DAAB) and SQL Server database communication with SQL Server databases via custom versions. In order to support distributed transactions, some intermediate business components are implemented in business services. For Microsoft .NET, this is a recommended way for distributed transactions. However, not all classes extends the ServicedComponent class because all classes are implemented as a component of the enterprise service is performance overhead. When I published the .NET PET SHOP 2.0 used in the MiddleWare application server benchmark test, we received many feedbacks that the architecture should be optimized to more suitable for large-scale enterprises. Feedback comparison focus includes:

• Create a fully abstract data layer without importing data specific classes in the intermediate layer.

• Data access layers to Oracle can be transparently used as the same business layer and the UI layer as the SQL Server version.

• Fully extract the web session status from the business logic layer and the data layer so that the rear-end component of the application can be physically distributed to other computers other than the web server, or from other types of clients such as Windows based on Windows. Clients and web-based clients are reused.

• Divide the application module into multiple namespaces and physical assemblies.

• Feedback from other aspects.

.NET PET SHOP 3.0 architecture

Figure 8. .NET PET SHOP 3.0 application architecture

Application field

Table 3. Application fields in PET SHOP solutions

range

use

.NET implementation

User interface components

Capture data input from the user and display the data returned by the backend system. They also handle simple positioning. See user interface components.

ASP.NET web form, user control, and server controls. These configurations can clearly separate the designer's HTML and UI code such as an event handler of the button.

User interface processing

Control the user positioning and processing flow with backend business objects. Also handle the management of user session data. Refer to the user processing components.

These are implemented with C # class. Session status management is processed by ASP.NET.

Business component

Implement the application business logic

These are implemented with C # class

Business entity

The thin data class that passes the data between the applications. See business entity components.

These are implemented with C # class, each field is disclosed in the form of attributes. Each class is marked as "serializable" and enables inter-process transfer.

Data Access Layer Components

Handling interactions with backend data storage area, including databases, message processing systems, and the like.

These components handle interactions with the backend data storage area, including databases, message processing systems, etc., are implemented with four C # items:

• A set of interface classes, each data access method to be disclosed is available.

• Implementation of the SQL Server interface.

• Implementation of Oracle 9i interface.

• A set of factory classes, SQL Server, or Oracle that loads properly implemented.

Microsoft Visual Studio .NET Solution

Figure 9 shows the layout of the Microsoft Visual Studio .NET solution to the .NET PET SHOP application. Each element or layer of the app has its own project, so that the solution can manage and clearly define where the new categories used in the application should be put, the old class can be found.

Figure 9. Visual Studio .NET Application Solutions Table 4 lists the purposes of each item:

Table 4. Visual Studio project in PET SHOP solutions

project

use

BLL

Business logic components store

Configtool

Management application used to encrypt the connection string and create an event log source

Dalfactory

Use to determine which type of database access assembly

IDAL

A set of interfaces that each DAL implementation is implemented

MODEL

Thin data or business entity

Oracles

Oracle-specific PET Shop Dal implementation, use iDAL interface

Post-build

Run the compiled project, such as adding the assembly to GAC or COM

Pre-build

Delete the assembly from the GAC or from the item from the COM logout assembly

SQLServerdal

Microsoft SQL Server-specific PET Shop Dal implementation, use IDAL interface

Utility

A set of helper classes, including DPAPI packaging

Web

Web page and control

Solution items

Miscenters used to build applications, such as PET Shop.snk key files used to sign an application assembly

Database portability

One of the key needs of this version Microsoft .Net PET SHOP is to provide an application implementation that supports Oracle and SQL Server databases. When designing a database access mechanism for an application, we can choose which database provider should use; you can use a generic OLE-DB managed provider or database-specific optimized performance .NET managed provider, such as .NET Framework 1.1 The SQL Server and Oracle managed providers provided are available. One of the key needs of the application is to create a high-performance solution, so we choose the application of the database itself. Net managed provider. About the performance difference analysis between the hosting provider and the general OLE-DB provider, the reader can refer to the USING .NET Framework Data Provider for Oracle To Improve .NET Application Performance, the document illustrates that the vendor-specific provider can be equivalent. OLE-DB provides two to three times. Considerations when choosing a database-specific access class is that we need to write a separate data access layer for each database platform to be supported, so the application will contain more code. Although two data access layers share a lot of public code, it is still necessary to significantly respectively target specific databases (Oracle or SQL Server 2000).

In order to simplify the use of the database access class, we choose GOF (Translation: Refers to Erich Gamma Waiting for the factory design mode outlined by the design mode "book), and loads the correct data access object at runtime by reflection dynamics. The factory design model is implemented: create a C # interface, where each method that must be disclosed in the database access class must declare a method. For each database to be supported, create a specific class that implements a specific code of the database to perform each of the interfaces also known as "Agreement". In order to support the run, it is necessary to create a third class, which is the factory class, which is read from the configuration file to determine which assembly should be loaded. By the reflection namespace of .NET, you can load an instance of a particular assembly and use the assembly to create an instance of an object. In order to make the application more secure, provide better support for version control, we can add "evidence" to add program set files to be loaded in the application configuration file (that is, web.config.), Which means. The NET framework will only load our assembly that we have signed during the compilation period and have the correct version number. Figure 10 illustrates how business logic classes, factory classes, and database access classes are interoperable. The most important advantage of this creating solution is that the database access class can be compiled after the business logic class, as long as the data access class implements the IDAL interface. This means that if you want to create a DB2 version of the application, we don't need to change the business logic layer (or UI layer). The steps to create a DB2 compatible version are as follows: 1. Create a DB2 database access class, which should implement the IDAL interface.

2. Compile the DB2 Access Class into an assembly.

3. Test and deploy a new data assembly to a running server.

4. Change the configuration file, point to the new database access class.

There is no need to change or recompile the business logic component.

Figure 10. Implementation of DAL factory class in .NET PET SHOP

Stored procedure

Usually we recommend that customers use stored procedures to access tables in the database. The reason is as follows:

• The stored procedure provides a simple mechanism for packaging queries.

• Modify the query can be performed without changing the data access code.

• DBA can easily see what SQL statement is being executed.

• The stored procedure is generally safer, and it is easier to control database access.

• Use the stored procedure to avoid multiple round trips to the client by sending multiple requests during the stored procedure.

• The stored procedure typically provides optimal performance compared to SQL generated by the intermediate layer.

• The stored procedure provides an excellent way to encapsulate XML queries and XML input parameters.

The disadvantage of the stored procedure is that they are often proprietary and cannot be transplanted across platforms.

However, to maximize investment that has been spent on database software and hardware, developers tend to optimize SQL used in applications, regardless of SQL is generated in the stored procedure or in the middle layer. This has a good example, the unique number or identification number of the generated, because all databases support your own special mechanism, so SQL to generate unique numbers is often specific to the database. Generally there is always an alternative, but their execution speed is less than a proprietary solution.

For .NET PET SHOP, we consciously do not use stored procedures in the application, as this is considered to be a .NET solution in the MiddleWare benchmark test. Nothing. In fact, the performance difference in this area is small because the application is relatively simple, and most SQL statements have cocked in the database. However, the MiddleWare benchmark specification does not allow the use of stored procedures, even if it is just a simple SQL statement, therefore .NET PET SHOP 3.0 does not use stored procedures. Cache

The most effective way to improve database-driven applications is to avoid accessing databases for each request. ASP.NET provides a variety of caching mechanisms to improve performance in most applications. Two main ways to use cache in ASP.NET are output cache and data cache.

.NET cache option

The page-level output cache receives the response from the ASP.NET web page and stores the entire page into the cache. The page cache is designed to operate between the web layer and the intermediate layer, the result / data of the cache intermediate layer method, or cache the database called in the two-storey application. The first edition of .NET PET SHOP also provides a page-level output cache version and a non-buffer version. The third version only supports data cache, but can be easily changed to support output cache. For Windows Server 2003 and IIS 6.0, some output cached pages (those VaryByParm = "none" and Cache 'Anywhere' instructions can also cache in the kernel level, and the Internet client access is faster. In any case, any output cached page (kernel or non-kernel cache) Windows application server can perform less in the case where the resource (CPU) consumes less, because it is actually recreated page without processing.

ASP.NET Output Cache

The earliest .NET PET SHOP application, version 1.5, also uses a variant of a page-level output cache, which is a partial page cache or a segment cache to cache different areas of the page. For example, cache header information at the top of each page. However, the header information depends on the user being logged in (so two different versions of the page are cached). ASP.NET is easy to allow this operation to use the VaryByCustom properties in the 'OutputCache' instruction. Use VarybyCustom to override the getVaryByCustomString method to get a custom cache for header information.

ASP.NET data and object cache

Object Cache (Cache API) Allows the use of the .NET framework in the internal cache engine to store method calls or database queries. Since the application work pipeline has been deeply in-depth, the data cache may not provide the same performance improvement like the output cache, as the HTML page must be dynamically constructed for each request. However, it has been a good compromise between the complete dynamic pages and the reduction of database loads by memory non-volatile data. For example, you want to display the same data in different ways in two web pages, or in different pages of the same application in different ways to use the cached object or data.

ASP.NET Cache Monitoring

Monitor what happens in the ASP.NET cache system, there are several ways. The primary approach is to use PerfMon, but you can also use SQL Server to check the time of accessing the database, depending on the specific situation. In order to monitor the cache in PerfMon, select Output Cache Entries and Cache API Entries counters under the ASP.NET Application Performance Object, and add them to Perform. You can also monitor turnover rates and click rate in PerfMon, check whether or not to use a project in the cache. Table 5. .NET Cache Option Summary

Cache type

advantage

limit

Output cache

Provide best performance

The entire page output is cache

Fragment cache

(Cache User Control)

Real is simple. The entire page output is cache

Time invalid restriction

Cache API

Pages Different user controls can have different cache times

Cache controls can be shared across pages. Need to cache each user control

PET SHOP MIDDLEWARE benchmark cache rules

MiddleWare defines strict rules for reference test applications: what is capable of cache, how to cache. Generally, the page-level output cache is disabled, but some parts of the application allow intermediate layer data caches. The following data allows caches, no need to refresh from the database each request: Category information, product information, project information (except inventory data) and certain account information. For stock data, whenever Item added to the shopping cart or user positioning to the 'ItemDetails' page, the current amount in the inventory should reflect the latest value. For account information, usernames, and passwords are verified for each login attempt, the address used as billing information should also always refresh from the database to ensure that it is the latest in checkout processing. It means here that can be used to cache the results of most product search and browsing operations in the intermediate layer using a data / object cache set up a given period.

The second rule of the reference test should not allow the page-level output cache; should always be required to be re-creating the HTML to be rendered to the page. This is to test the ability of the application server to generate dynamic pages, not how fast the test server drags html from the cache.

PET SHOP 3.0 Cache Implementation

For this version of the app, we use the data cache in the ASPX page post-code code to cache the results of the intermediate layer (business logic layer) request. The following sample code illustrates how to access the ASP.NET cache API from cache search information. This example is based on the category query code in the PET SHOP application, category.aspx.cs. In PET SHOP, users can select one in five predefined pet categories to see a list of animals in this category. The first thing to do is to check if the data has been cached, which is implemented by using the category ID as a key to find an element in the data cache. If this element does not exist, or because the data has not been caught, or the current cache has expired, will return NULL. If the element exists, drag the data from the cache and convert to a suitable type. If the data is not in the cache, the intermediate layer query data is called. The result of the intermediate layer query is then added to the cache, the deadline is from now on 12 hours. Alternatively, the cache expires to another cache item according to the fixed time, or by providing a callback function that can be used to clear the cache.

// Get the category from the query string

String categoryKey =

WebComponents.cleanstring.inputText (Request ["CategoryID"], 50);

// Check to see if the contents are in the data cacheif (cache [categoryKey]! = Null) {

// if the data is already cached, then used the cached copy

Products.DataSource = (ilist) cache [categoryKey];

} else {

// if the data is not cached,

// Ten Create a New Products Object and Request the Data

Product product = new product ();

IList ProductsBycategory = Product.getProductSBycategory (CategoryKey);

// store the results of the call in the cache

// and set the time out to 12 Hours

Cache.Add (CategoryKey, ProductsBycategory, Null, DateTime.now.NODHOURS (12), cacheitempriority.high, null;

Products.DataSource = ProductsBycategory;

}

// bind the data to the control of THE CONTROL

Products.DATABIND ();

summary

The architecture of .NET PET SHOP has been improved, and the application can provide a more flexible solution in deployment selection, and applications can easily customize, adapt to changes in business models. Despite these changes, PET SHOP performance is roughly the same as version 2.0, which shows another feasible enterprise-level solution in J2EE. Through the functionality of the .NET PET SHOP and J2EE PET Store, architects, and developers, the best programming practices on their respective platforms are described, one-on-one compares .NET and J2EE. The upcoming MiddleWare benchmark test will test new .NET PET SHOP 3.0 implementation, which will compare it with two new J2EE-a CMP 2.0, another pure JSP / servlet architecture (not using EJB) performance . The test will be conducted by MiddleWare, publishing the server side running various J2EE applications. A J2EE expert jury will make this benchmark to ensure the fairness of the test product, and all implementations meet the norms and best criteria. In addition, the primary J2EE application server vendor has been invited to participate in this benchmark test, and they will evaluate the norms, provide implementation for testing, and perform fine-tuning and optimization on site, participate in the test process. Microsoft Selects a comprehensive participation in the second round of tests. You can find out the details of the first round of the Middleware Application Server test here, and the test is based on two reference test applications: early .NET PET Shop 2.0 and a BMP-based J2EE implementation, or downloads a complete report.

Appendix A: Changes from Version 2 to Version 3

project

Description

the reason

1

Create a Database Access Layer (DAL).

The business logic can be completely separated from the database access code, so you can change the database vendor without changing the business logic code.

2

Create a public project for all thin data classes (models). The model project contains only the thin class of the saved data, which can be used in each layer of the application, as a container for transmitting data. All model classes support serialization through the [Serializable] tag to add enhancement support for clustering and any future physical deployment.

3

Remove the reference to System.Web in the Components project.

This is a good design practice because the intermediate layer components can be used for different types of UIs.

4

Change some custom server controls to web user controls; however, the Pager control remains to customize server controls.

Header and title controls contain many HTML / UI contents, so it is easier to maintain if you implement the web user control. The PAGER control is processed by the operation of the query string, the use of data in the view status, so it is more appropriate as a custom server control.

5

Create a DAL implementation for Oracle.

In order to support the Oracle database, a specific Oracle DAL is created, you can use Oracle-specific drivers

6

The DAL layer now implements the factory model [GOF] to load the corresponding supplier specific DAL.

In order to hide the database used by the backend, use the factory method to return the interface to the DAL layer you want to use.

Seduce

All public fields in the model class are converted to attributes.

The storage mechanism of such a field can hide, if you want to see what function modifies some data, this provides a good place to add breakpoints in the code.

8

Create a Database Access Layer (DAL).

The business logic can be completely separated from the database access code, so you can change the database vendor without changing the business logic code.

9

Change all static methods to an example method.

Modify according to the feedback feedback

10

Change the version number in AssemblyInfo.cs to a specific version of the deployment.

The specified evidence is allowed when loading an assembly in the DalFactory object.

11

Adding a built-in and built steps in the Visual Studio .NET solution.

In this way, after the project is compiled, the GACUTIL and REGSVCS utilities can be run on the specific assembly.

12

The subscription business component is changed, and the mechanism is not implemented according to the function thereof.

It is more intuitive to understand the function of the components for other developers.

13

Create settings for configuring tool auxiliary applications.

You need to create an application event log source as an administrator group member. Ensure that the easiest way to complete is to provide a simple tool, you can run after deployment.

14

Modify the code to allow your account and product databases and the order database to use different DAL.

The response to the user should be able to use a hybrid database deployment model.

15

Add a page output cache in the page; however, it is deleted when the benchmark test.

Some users request to rewrite the VaryByCustom function to cache pages such as headings and header controls in the page of Default.aspx.

16

Add the processing flow control class to the web application.

According to the modification made by comment feedback, provide a single location for the web area such as an account or shopping cart to control positioning and status management.

转载请注明原文地址:https://www.9cbs.com/read-106453.html

New Post(0)