MIDP MIDlet Lifecycle
The MIDlet package defines Mobile Information
Device Profile applications and the interactions between the
application and the environment in which the application runs. An
application of the Mobile Information Device Profile is a
MIDlet .
Applications
The MIDP defines an application model to allow the limited resources of
the device to be shared by multiple MIDP applications, or MIDlets. It
defines what a MIDlet is, how it is packaged, what runtime environment
is available to the MIDlet, and how it should be behave so that the
device can manage its resources. The application model defines how
multiple MIDlets forming a suite can be packaged together and share
resources within the context of a single Java Virtual Machine. Sharing
is feasible with the limited resources and security framework of the
device since they are required to share class files and to be subject
to a single set of policies and controls.
MIDP MIDlet Suite
A MIDP application MUST use only functionality specified by the MIDP
specification as it is developed, tested, deployed, and run.
The elements of a MIDlet suite are:
-
Runtime execution environment
-
MIDlet suite packaging
-
Application descriptor
-
Application lifecycle
Each device is presumed to implement the functions required by its
users to install, select, run, and remove MIDlets. The term application
management software is used to refer collectively to these device
specific functions. The application
management software provides an environment in which the MIDlet is
installed, started, stopped, and uninstalled. It is responsible for
handling errors during the installation, execution, and removal of
MIDlet suites and interacting with the user as needed. It provides to
the MIDlet(s) the Java runtime environment required by the MIDP
Specification.
One or more MIDlets MAY be packaged in a single JAR file. Each MIDlet
consists of a class that extends the MIDlet
class and other classes as may be needed by the MIDlet.
The manifest in the JAR file contains attributes that are used
during installation and execution of MIDlets.
The MIDlet is the entity that is launched
by the application management software. When a MIDlet suite is
invoked, a Java Virtual Machine is needed on which the classes can be
executed. A new instance of the MIDlet is created by the application
management software and used to direct the MIDlet to start, pause, and
destroy itself.
Sharing of data and other information between MIDlets is controlled by
the individual APIs and their implementations. For example, the Record
Management System API specifies the methods that are used when
the record stores associated with a MIDlet suite are shared among
MIDlets.
MIDlet Suite Security
The MIDP 1.0 specification constrained each MIDlet suite to
operate in a sandbox wherein all of the APIs available to the
MIDlets would prevent access to sensitive functions of the
device. That sandbox concept is used in this specification and
all untrusted MIDlet suites are subject to its limitations.
Every implementation of this specification MUST support running
untrusted MIDlet suites.
MIDP introduces the concept of trusted applications that
may be permitted to use APIs that are considered sensitive and
are restricted. If and when a device determines that a MIDlet suite
can be trusted the device allows access as indicated by the
policy.
Security for MIDP Applications
section describes the concepts and capabilities of untrusted and
trusted applications.
MIDP Execution Environment
The MIDP defines the execution environment provided to MIDlets. The
execution environment is shared by all MIDlets within a MIDlet suite,
and any MIDlet can interact with other MIDlets packaged together. The
application management software initiates the applications and makes
the following available to the MIDlet:
-
Classes and native code that implement the CLDC, including a Java
Virtual Machine
-
Classes and native code that implement the MIDP runtime
-
All classes from a single JAR file for execution
-
Non-class files from a single JAR file as resources
-
Contents of the descriptor file, when it is present
-
Any other APIs available on the device such as implementations
of additional JSRs, Licensee Open Classes, Optional Packages,
etc.
The CLDC and Java Virtual Machine provide multi-threading, locking and
synchronization, the execution of byte codes, dispatching of methods,
etc. A single VM is the scope of all policy, naming, and resource
management. If a device supports multiple VMs, each may have its own
scope, naming, and resource management policies. MIDlet Suites
MUST NOT contain classes that are in packages defined by the
CLDC or MIDP.
The MIDP provides the classes that implement the MIDP APIs.
The implementation MUST ensure that the application
programmer cannot override, modify, or add any classes
to these protected system packages.
A single JAR file contains all of the MIDlet's classes. The MIDlet may
load and invoke methods from any class in the JAR file, in the MIDP, or
in the CLDC. All of the classes within these three scopes are shared in
the execution environment of the MIDlets from the JAR file. All states
accessible via those classes are available to any Java class running on
behalf of the MIDlet. There is a single space containing the objects of
all MIDlets, MIDP, and CLDC in use by the MIDlet suite. The usual Java
locking and synchronization primitives SHOULD be used when necessary to
avoid concurrency problems. Each library will specify how it handles
concurrency and how the MIDlet should use it to run safely in a
multi-threaded environment.
The class files of the MIDlet are only available for execution and can
neither be read as resources nor extracted for re-use. The
implementation of the CLDC may store and interpret the contents of the
JAR file in any manner suitable.
The files from the JAR file that are not Java class files are made
available using
java.lang.Class.getResourceAsStream .
For example, the manifest would be available in this manner.
The contents of the MIDlet descriptor file, when it is present, are made
available via the
javax.microedition.midlet.MIDlet.getAppProperty method.
MIDlet Suite Packaging
One or more MIDlets are packaged in a single JAR file that
includes:
-
A manifest describing the contents
-
Java classes for the MIDlet(s) and classes shared by the MIDlets
-
Resource files used by the MIDlet(s)
The developer is responsible for creating and distributing the
components of the JAR file as appropriate for the target user, device,
network, locale, and jurisdiction. For example, for a particular
locale, the resource files would be tailored to contain the strings and
images needed for that locale.
The JAR manifest defines attributes that are used by the application
management software to identify and install the MIDlet suite and as
defaults for attributes not found in the application descriptor. The
attributes are defined for use in both the manifest and the optional
application descriptor.
The predefined attributes listed below allow the application management
software to identify, retrieve, install, and invoke the MIDlet.
MIDlet Attributes
Attribute Name
|
Attribute Description
|
MIDlet-Name
|
The name of the MIDlet suite that identifies the MIDlets to the
user.
|
MIDlet-Version
|
The version number of the MIDlet suite. Version numbers
are formatted so they can be used by
the application management software for install and
upgrade uses, as well as communication with the user.
|
MIDlet-Vendor
|
The organization that provides the MIDlet suite.
|
MIDlet-Icon
|
The case-sensitive absolute name of a PNG file within the
JAR used to represent the MIDlet
suite. It SHOULD be used when the Application Management Software
displays an icon to identify the suite.
|
MIDlet-Description
|
The description of the MIDlet suite.
|
MIDlet-Info-URL
|
A URL for information further describing the MIDlet suite.
The syntax and meaning MUST conform to RFC2396 and RFCs that
define each scheme.
|
MIDlet-<n>
|
The name, icon, and class of the nth MIDlet in the JAR file separated
by a comma. The lowest value of <n> MUST be 1 and consecutive
originals MUST be used.
The first missing entry terminates the list.
Any additional entries are ignored.
Leading and trailing spaces in
name, icon and class are ignored.
-
Name is used to identify this MIDlet to the user.
The name must be present and be non-null.
-
Icon is the case-sensitive absolute path name of an
image (PNG) within the JAR for the icon of the nth
MIDlet. The icon may be omitted.
-
Class is the name of the class extending the
javax.microedition.midlet.MIDlet class for
the nth MIDlet. The classname MUST be non-null and
contain only characters for Java class names. The class
MUST have a public no-args constructor. The class name
IS case sensitive.
|
MIDlet-Jar-URL
|
The URL from which the JAR file can be loaded. The syntax
and meaning MUST conform to RFC2396 and RFCs that define
each scheme. Both absolute and relative URLs MUST be
supported. The context for a relative URL is the URL from
which this application descriptor was loaded.
|
MIDlet-Jar-Size
|
The number of bytes in the JAR file.
|
MIDlet-Data-Size
|
The minimum number of bytes of persistent data required by the MIDlet.
The device may provide additional storage according to its own policy.
The default is zero.
|
MicroEdition-Profile
|
The J2ME profiles required, using the same format and
value as the System property
microedition.profiles (for example "MIDP-2.1").
The device must implement all of the profiles
listed. If any of the profiles are not implemented the
installation MUST fail. Multiple profiles are separated
with a blank (Unicode U+0020).
|
MicroEdition-Configuration
|
The J2ME Configuration required using the same format and value as the
System property microedition.configuration
(for example "CLDC-1.0").
|
MIDlet-Permissions
|
Zero or more permissions that are critical to the function
of the MIDlet suite.
See the MIDlet Suite
Security section for details of usage.
|
MIDlet-Permissions-Opt
|
Zero or more permissions that are non-critical to the
function of the MIDlet suite.
See the MIDlet Suite
Security section for details of usage.
|
MIDlet-Push-<n>
|
Register a MIDlet to handle inbound connections.
Refer to
javax.microedition.io.PushRegistry for details.
|
MIDlet-Install-Notify
|
Refer to the
OTA Specification for details.
|
MIDlet-Delete-Notify
|
Refer to the
OTA Specification for details.
|
MIDlet-Delete-Confirm
|
Refer to the
OTA Specification for details.
|
Some attributes use multiple values, for those attributes the
values are separated by a comma (Unicode U+002C) except where noted.
Leading and trailing whitespace (Unicode U+0020) and tab
(Unicode U+0009) are ignored on each value.
Version numbers have the format Major.Minor[.Micro] (X.X[.X]), where
the .Micro portion MAY be omitted. (If the .Micro portion is not
omitted, then it defaults to zero). In addition, each portion of the
version number is allowed a maximum of two decimal digits (i.e.,
0-99).
Version numbers are described in the
the Java(TM) Product Versioning Specification
http://java.sun.com/products/jdk/1.2/docs/guide/versioning/spec/VersioningSpecification.html.
For example, 1.0.0 can be used to specify the first version of a MIDlet
suite. For each portion of the version number, leading zeros are not
significant. For example, 08 is equivalent to 8. Also, 1.0 is
equivalent to 1.0.0. However, 1.1 is equivalent to 1.1.0, and not
1.0.1.
A missing MIDlet-Version tag is assumed to be 0.0.0, which means that
any non-zero version number is considered as a newer version of the
MIDlet suite.
JAR Manifest
The manifest provides information about the contents of the JAR file.
JAR file formats and specifications are available at
http://java.sun.com/products/jdk/1.2/docs/guide/jar/index.html.
Refer to the JDK JAR and manifest documentation for the syntax and
related details. MIDP implementations MUST implement handling of
lines longer than 72 bytes as defined in the manifest
specification.
An attribute MUST not appear more than once within the manifest.
If an attribute is duplicated the effect is unspecified.
Manifest attributes are passed to the MIDlet when requested
using the MIDlet.getAppProperty method, unless the
attribute is duplicated in the application descriptor, for
handling of duplicate attributes see the "Application
Descriptor" section.
The manifest MUST contain the following attributes:
-
MIDlet-Name
-
MIDlet-Version
-
MIDlet-Vendor
The manifest or the application descriptor MUST contain the following
attributes:
-
MIDlet-<n> for each MIDlet
-
MicroEdition-Profile
-
MicroEdition-Configuration
The manifest MAY contain the following:
-
MIDlet-Description
-
MIDlet-Icon
-
MIDlet-Info-URL
-
MIDlet-Data-Size
-
MIDlet-Permissions
-
MIDlet-Permissions-Opt
-
MIDlet-Push-<n>
-
MIDlet-Install-Notify
-
MIDlet-Delete-Notify
-
MIDlet-Delete-Confirm
-
Any application-specific attributes that do not begin with
MIDlet- or MicroEdition-
For example, a manifest for a hypothetical suite of card games would
look like the following example:
MIDlet-Name: CardGames
MIDlet-Version: 1.1.9
MIDlet-Vendor: CardsRUS
MIDlet-1: Solitaire, /Solitare.png, org.cardsrus.games.Solitare
MIDlet-2: JacksWild, /JacksWild.png, org.cardsrus.games.JacksWild
MicroEdition-Profile: MIDP-2.1
MicroEdition-Configuration: CLDC-1.0
Solitaire-Author: John Q. Public
|
MIDlet Classes
All Java classes needed by the MIDlet are be placed in the JAR file
using the standard structure, based on mapping the fully qualified
class names to directory and file names. Each period is converted to a
forward slash ( / ) and the .class
extension is appended. For example, a class
com.sun.microedition.Test
would be placed in the JAR file with the name
com/sun/microedition/Test.class
.
Application Descriptor
Each JAR file MAY be accompanied by an application descriptor.
The application descriptor is used in conjunction with the JAR
manifest by the application management software to manage the MIDlet and
is used by the MIDlet itself for configuration specific attributes. The
descriptor allows the application management software on the device to
verify that the MIDlet is suited to the device before loading the full
JAR file of the MIDlet suite. It also allows configuration-specific
attributes (parameters) to be supplied to the MIDlet(s) without
modifying the JAR file.
To allow devices to dispatch an application descriptor to the MIDP
application management software, a file extension and
MIME type are registered with the IANA:
-
The file extension of an application descriptor file is
jad
-
The MIME type of an application descriptor file is
text/vnd.sun.j2me.app-descriptor .
A predefined set of attributes is
specified to allow the application management software to identify,
retrieve, and install the MIDlet(s). All attributes appearing in the
descriptor file are made available to the MIDlet(s). The developer may
use attributes not beginning with MIDlet- or
MicroEdition- for
application-specific purposes.
Attribute names are case-sensitive and MUST match exactly.
An attribute MUST NOT appear more than once within the manifest.
If an attribute is duplicated the effect is unspecified.
The MIDlet retrieves attributes by name by calling the
MIDlet.getAppProperty method.
The application descriptor MUST contain the following attributes:
-
MIDlet-Name
-
MIDlet-Version
-
MIDlet-Vendor
-
MIDlet-Jar-URL
-
MIDlet-Jar-Size
The application descriptor MAY contain:
-
MIDlet-<n> for each MIDlet
-
MicroEdition-Profile
-
MicroEdition-Configuration
-
MIDlet-Description
-
MIDlet-Icon
-
MIDlet-Info-URL
-
MIDlet-Data-Size
-
MIDlet-Permissions
-
MIDlet-Permissions-Opt
-
MIDlet-Push-<n>
-
MIDlet-Install-Notify
-
MIDlet-Delete-Notify
-
MIDlet-Delete-Confirm
-
Any application-specific attributes that do not begin with
MIDlet- or MicroEdition-
The mandatory attributes MIDlet-Name, MIDlet-Version, and MIDlet-Vendor
MUST be duplicated in the descriptor and manifest files since they
uniquely identify the application. If they are
not identical (not from the same application), then the JAR MUST NOT be
installed.
Duplication of other manifest attributes in the application
descriptor is not required and their
values MAY differ even though both the manifest and descriptor files
contain the same attribute for
untrusted
MIDlet suites.
If the MIDlet suite is not trusted the value from the descriptor
file will override the value from the manifest file.
If the MIDlet suite is
trusted
then the values in the application descriptor
MUST be identical to the corresponding attribute values in the Manifest.
MIDlets MUST NOT add any attributes to the manifest or the
Application Descriptor that start with MIDlet- or
MicroEdition- other than those defined in the relevant
Configuration and Profiles (e.g. CLDC and MIDP) specifications.
Unrecognized attributes MUST be ignored by the AMS.
Generally speaking, the format of the application descriptor is a
sequence of lines consisting of an attribute name followed by a colon,
the value of the attribute, and a carriage return. White space is
ignored before and after the value. The order of the attributes is
arbitrary.
The application descriptor MAY be encoded for transport or storage and
MUST be converted to Unicode before parsing, using the rules below. For
example, an ISO-8859-1 encoded file would need to be read through the
equivalent of java.io.InputStreamReader
with the appropriate encoding. The default character encoding for
transporting a descriptor is UTF-8. Descriptors retrieved via HTTP,
if that is supported, SHOULD use the standard HTTP content negotiation
mechanisms, such as the Content-Encoding header and the Content-Type
charset parameter to convert the stream to UCS-2.
BNF for Parsing Application Descriptors
appldesc: *attrline
attrline: attrname ":" [WSP] attrvalue [WSP] newlines
attrname: 1*<any Unicode char except
CTLs or separators>
attrvalue: *valuechar | valuechar *(valuechar | WSP) valuechar
valuechar: <any valid Unicode character,
excluding CTLS and WSP>
newlines = 1*newline ; allow blank lines to be ignored
newline: CR LF | LF
CR = <Unicode carriage return (U+000D)>
LF = <Unicode linefeed (U+000A)>
WSP: 1*( SP | HT )
SP = <Unicode space (U+0020)>
HT = <Unicode horizontal-tab (U+0009)>
CTL = <Unicode characters
U+0000 - U+001F and U+007F>
separators: "(" | ")" | "<" |
">" | "@" |
"," | ";" | ":" |
"'" | <">|
"/" | "[" | "]" |
"?" | "=" |
"{" | "}" | SP | HT
|
For example, an application descriptor for a hypothetical suite of card
games would look look like the following example:
MIDlet-Name: CardGames
MIDlet-Version: 1.1.9
MIDlet-Vendor: CardsRUS
MIDlet-1: Solitaire, /Solitare.png, com.cardsrus.org.Solitare
MIDlet-2: JacksWild, /JacksWild.png, com.cardsrus.org.JacksWild
MicroEdition-Profile: MIDP-2.1
MicroEdition-Configuration: CLDC-1.0
MIDlet-Description: Really cool card games
MIDlet-Jar-URL: http://www.cardsrus.com/games/cardgames.jar
MIDlet-Jar-Size: 7378
MIDlet-Data-Size: 256
|
Application Lifecycle
Each MIDlet MUST extend the MIDlet
class. The MIDlet
class allows for the orderly starting, stopping, and cleanup of the
MIDlet. The MIDlet can request the arguments from the application
descriptor to communicate with the application management software. A
MIDlet suite MUST NOT have a public static void main()
method. If it exists, it MUST be ignored by the application management
software. The application management software provides the initial
class needed by the CLDC to start a MIDlet.
When a MIDlet suite is installed on a device, its classes, resource
files, arguments, and persistent storage are kept on the device and
ready for use. The MIDlet(s) are available to the user via the device's
application management software.
When the MIDlet is run, an instance of the MIDlet's primary class is
created using its public no-argument constructor, and the methods of
the MIDlet
are called to sequence the MIDlet through its various states. The
MIDlet can either request changes in state or notify the application
management software of state changes via the MIDlet
methods. When the MIDlet is finished or terminated by the application
management software, it is destroyed, and the resources it used can be
reclaimed, including any objects it created and its classes. The
MIDlet MUST NOT call System.exit
, which will throw a SecurityException
when called by a MIDlet.
The normal states of Java classes are not affected by these classes as
they are loaded. Referring to any class will cause it to be loaded, and
the normal static initialization will occur.
Class in
javax.microedition.midlet
|
Description
|
MIDlet
|
Extended by a MIDlet to allow the application management software to
start, stop, and destroy it.
|
MIDletStateChangeException
|
Thrown when the application cannot make the change requested.
|
MIDlet lifecycle
The MIDlet lifecycle defines the
protocol between a MIDlet and its environment through
the following:
-
A simple well-defined state machine
-
A concise definition of the MIDlet's states
-
APIs to signal changes between the states
MIDlet Lifecycle Definitions
The following definitions are used in the MIDlet
lifecycle:
-
application management software
- a part of the device's software operating environment that
manages MIDlets . It maintains the MIDlet state
and directs the MIDlet
through state changes.
-
MIDlet - a MIDP application on the device.
The MIDlet can signal the application management
software about whether is it wants to run or has completed. A
MIDlet has no knowledge of other MIDlet s
through the MIDlet API.
-
MIDlet States - the states a
MIDlet can have are defined by the transitions allowable
through the MIDlet interface. More specific
application states are known only to the application.
MIDlet States
The MIDlet state machine is designed to ensure that
the behavior of an application is consistent and as close as
possible to what device manufactures and users expect,
specifically:
-
The perceived startup latency of an application SHOULD be very
short.
-
It SHOULD be possible to put an application into a state where
it is not active.
-
It SHOULD be possible to destroy an application at any time.
The valid states for
MIDlet s are:
State Name
|
Description
|
Paused
|
The MIDlet is initialized and is quiescent. It
SHOULD not be holding or using any shared resources. This state is
entered:
-
After the MIDlet has been created using
new . The public no-argument constructor for the
MIDlet is called and returns without throwing an exception.
The application typically does little or no initialization in this
step. If an exception occurs, the application immediately enters
the Destroyed state and is discarded.
-
From the Active state after the
MIDlet.pauseApp() method is called from the
AMS and returns successfully.
-
From the Active state when the
MIDlet.notifyPaused() method returns successfully to the
MIDlet .
-
From the Active state if startApp throws an
MIDletStateChangeException .
|
Active
|
The MIDlet is functioning normally. This state is
entered:
|
Destroyed
|
The MIDlet has released all of its resources and
terminated. This state is entered:
-
When the AMS called the
MIDlet.destroyApp() method and returns
successfully, except in the case when the
unconditional argument is false and a
MIDletStateChangeException is thrown. The
destroyApp() method shall release all
resources held and perform any necessary cleanup so it
may be garbage collected.
-
When the MIDlet.notifyDestroyed() method returns
successfully to the application. The MIDlet must have
performed the equivalent of the MIDlet.destroyApp()
method before calling MIDlet.notifyDestroyed() .
Note: This state is only entered once.
|
The states and transitions for a MIDlet are:
MIDlet Lifecycle Model
A typical sequence of
MIDlet execution is:
Application Management Software
|
MIDlet
|
The application management software creates a new instance of a
MIDlet .
|
The default (no argument) constructor for the
MIDlet is called; it is in the Paused state.
|
The application management software has decided that it is an
appropriate time for the MIDlet to run, so it calls
the MIDlet.startApp method for it to enter the Active
state.
|
The MIDlet acquires any resources it needs and
begins to perform its service.
|
The application management software wants the MIDlet to
significantly reduce the amount of resources it is
consuming, so that they may temporarily be used by other
functions on the device such as a phone call or running
another MIDlet. The AMS will signal this request to the
MIDlet by calling the MIDlet.pauseApp
method. The MIDlet should then reduce its resource
consumption as much as possible.
|
The MIDlet stops performing its service and might
choose to release some resources it currently holds.
|
The application management software has determined that the
MIDlet is no longer needed, or perhaps needs to make
room for a higher priority application in memory, so it signals the
MIDlet that it is a candidate to be destroyed by
calling the MIDlet.destroyApp method.
|
If it has been designed to do so, the MIDlet saves
state or user preferences and performs clean up.
|
MIDlet Interface
-
pauseApp - the MIDlet SHOULD release
any temporary resources and become passive
-
startApp - the MIDlet
SHOULD acquire any resources it needs and resume
-
destroyApp - the MIDlet SHOULD save
any state and release all resources
-
notifyDestroyed - the MIDlet notifies
the application management software that it has cleaned up and is
done
-
notifyPaused - the MIDlet notifies the
application management software that it has paused
-
resumeRequest - the MIDlet asks
application management software to be started again
-
getAppProperty - gets a named property from the
MIDlet
Application Implementation Notes
The application SHOULD take measures to avoid race conditions in
the execution of the MIDlet methods. Each method may
need to synchronize itself with the other methods avoid concurrency
problems during state changes.
Example MIDlet Application
The example uses the MIDlet lifecycle to do a simple measurement
of the speed of the Java Virtual Machine.
import javax.microedition.midlet.*;
/**
* An example MIDlet runs a simple timing test
* When it is started by the application management software it will
* create a separate thread to do the test.
* When it finishes it will notify the application management software
* it is done.
* Refer to the startApp, pauseApp, and destroyApp
* methods so see how it handles each requested transition.
*/
public class MethodTimes extends MIDlet implements Runnable {
// The state for the timing thread.
Thread thread;
/**
* Start creates the thread to do the timing.
* It should return immediately to keep the dispatcher
* from hanging.
*/
public void startApp() {
thread = new Thread(this);
thread.start();
}
/**
* Pause signals the thread to stop by clearing the thread field.
* If stopped before done with the iterations it will
* be restarted from scratch later.
*/
public void pauseApp() {
thread = null;
}
/**
* Destroy must cleanup everything. The thread is signaled
* to stop and no result is produced.
*/
public void destroyApp(boolean unconditional) {
thread = null;
}
/**
* Run the timing test, measure how long it takes to
* call a empty method 1000 times.
* Terminate early if the current thread is no longer
* the thread from the
*/
public void run() {
Thread curr = Thread.currentThread(); // Remember which thread is current
long start = System.currentTimeMillis();
for (int i = 0; i < 1000000 && thread == curr; i++) {
empty();
}
long end = System.currentTimeMillis();
// Check if timing was aborted, if so just exit
// The rest of the application has already become quiescent.
if (thread != curr) {
return;
}
long millis = end - start;
// Reporting the elapsed time is outside the scope of this example.
// All done cleanup and quit
destroyApp(true);
notifyDestroyed();
}
/**
* An Empty method.
*/
void empty() {
}
}
@since MIDP 1.0
|