Alert.png The wiki is deprecated and due to be decommissioned by the end of September 2022.
The content is being migrated to other supports, new updates will be ignored and lost.
If needed you can get in touch with EGI SDIS team using operations @ egi.eu.

Difference between revisions of "ROCCI-core Documentation"

From EGIWiki
Jump to navigation Jump to search
(Replaced content with "= OCCI Classes = This page is no longer maintained. See [https://github.com/the-rocci-project/rOCCI-core the-rocci-project/rOCCI-core].")
Line 1: Line 1:
= OCCI Classes =
= OCCI Classes =


This is an overview. More complex generated documentation for ''rOCCI-core'' classes is available at [http://rubydoc.info/github/gwdg/rOCCI-core/]
This page is no longer maintained. See [https://github.com/the-rocci-project/rOCCI-core the-rocci-project/rOCCI-core].
 
== Resources ==
 
The basic classes to work with are those extending class <code>Occi::Core::Resource</code>, representing basic cloud resources:
 
* <code>Occi::Infrastructure::Compute</code>
* <code>Occi::Infrastructure::Network</code>
* <code>Occi::Infrastructure::Storage</code>
 
On instantiation they can be augmented with the following properties. Most of the properties can also be set later along the way:
 
Occi::Core::Resource.new(kind, mixins, attributes, actions, links, location)
 
The easiest way to instantiate a <code>Resource</code> is to call its constructor, for instance for <code>Compute</code>:
 
Occi::Infrastructure::Compute.new
 
It is also possible to call the constructor to the parent <code>Resource</code> class and pass <code>kind</code> as an argument:
 
Occi::Core::Resource.new "http://schemas.ogf.org/occi/infrastructure#compute"
 
which allows your code to be more generic in working with different resource kinds.
 
== Links ==
 
Links&mdash;descendants of class <code>Occi::Core::Link</code>&mdash;constitute relationships between resource instances. There are, essentially, two kinds of links:
* <code>Occi::Infrastructure::Storagelink</code> connecting ''Compute'' with ''Storage'' resources
* <code>Occi::Infrastructure::Networkinterface</code> connecting ''Compute'' with ''Network''
 
'''TODO:''' ''How to instantiate a link''
 
== Mixins ==
 
Mixins extend the functionality of vanilla classes. Currently the following mixin templates are available:
* <code>Occi::Infrastructure::Resource_tpl.mixin</code>
* <code>Occi::Infrastructure::Os_tpl.mixin</code>
 
'''TODO:''' ''Short note on purpose for each mixin template above. Possibly also list other planned mixins, if any.''
 
Mixin templates can be applied to classes on instantiation. A minimalistic example to instantiate an (otherwise empty) <code>Compute</code> class and add a mixin with template <code>Os_tpl</code> could be put together as follows:
 
Occi::Core::Resource.new("http://schemas.ogf.org/occi/infrastructure#compute", [Occi::Infrastructure::Os_tpl.mixin], {}, [], [], nil)
 
The mixin can also be applied to an existing instance with the following:
 
comp=Occi::Infrastructure::Compute.new
comp.mixins << Occi::Infrastructure::Os_tpl.mixin
 
== Actions ==
 
Actions (instances of class <code>Occi::Core::Action</code>) are operations (to be) performed with respect to resource objects. Different actions are supported for different kinds of resources. The following actions are defined:
 
* '''<code>Compute</code>'''
** <code>start, stop, restart, suspend</code>
* '''<code>Storage</code>'''
** <code>online, offline, backup, snapshot, resize</code>
* '''<code>Network</code>'''
** <code>up, down</code>
* '''<code>Storagelink</code>'''
** <code>online, offline</code>
* '''<code>Networkinterface</code>'''
** <code>up, down</code>
 
Actions are governed by attributes specific to each action. For instance the <code>restart</code> action is controlled with:
 
restart.attributes['method'] = {:mutable => true,
                                :pattern => 'graceful|warm|cold',
                                :default => 'cold'}
 
'''TODO:''' Rendering
 
'''TODO:''' Make this section say something meaningful.
 
== Rendering ==
''rOCCI-core'' classes provide methods for rendering their contents into messages in various supported formats. Essentially there are the following methods:
* <code>to_text()</code> to produce a plain-text rendering of the object
* <code>to_header()</code> to produce a [http://rubygems.org/gems/hashie <code>Hashie::Mash</code>] holding the rendering of the object as an HTTP header
* <code>to_json()</code> to produce a string holding the rendering of the object in the JSON format
* <code>as_json()</code> to produce a [http://rubygems.org/gems/hashie <code>Hashie::Mash</code>] holding the rendering of the object in the JSON format
 
For instance, a <code>Compute</code> resource can be easily instantiated and then rendered in JSON as a [http://rubygems.org/gems/hashie <code>Hashie::Mash</code>] by calling:
 
res = Occi::Infrastructure::Compute.new
res.as_json
 
Similarly, an <code>Action</code>, for instance, can be rendered in an HTTP header by calling:
 
act =
act.to_header
 
'''TODO:''' finish the instantiation of the action
 
''Note: While there is support for [[Rocci-Core-Parts#ovfova-files|parsing OVF/OVA files]], the reverse operation, i.e. OVF/OVA rendering, is not supported.''
 
'''TODO:''' Confirm the above is correct
 
= Parser =
 
The parser processes input in various formats and produces ''rOCCI-core'' collections.
 
== OCCI Messages ==
 
The <code>Occi::Parser</code> supports the following content types for OCCI-compliant messages:
* <code>text/plain</code> (HTTP body)
* <code>text/occi</code> (HTTP headers)
* <code>application/occi+json</code>
* <code>application/xml</code>
 
The parsing operation is carried out by the <code>parse()</code> method whose attributes are as follows:
 
Occi::Parser.parse(media_type, body, category, entity_type, header)
 
For instance, let us have a message of type <code>text/plain</code>:
 
compute_text_plain = %Q|Category: compute;scheme="http://schemas.ogf.org/occi/infrastructure#";class="kind" Category: compute;scheme="http://opennebula.org/occi/infrastructure#";class="mixin" X-OCCI-Attribute: occi.core.id="0953b280-28ac-5d77-abe7-5fb67118c01c" X-OCCI-Attribute: occi.core.title="one-33064" X-OCCI-Attribute: occi.compute.cores=1 X-OCCI-Attribute: occi.compute.memory=0.256 X-OCCI-Attribute: occi.compute.architecture="x86" X-OCCI-Attribute: occi.compute.speed=1 X-OCCI-Attribute: occi.compute.state="active" X-OCCI-Attribute: org.opennebula.compute.cpu=1.0 Link: </storage/e60aa2b8-0c86-5973-b93e-30c5c46d6eac>;rel="http://schemas.ogf.org/occi/infrastructure#storage";self="/storagelink/b2f7f1de-c60c-5b08-879c-81f52429c4ef";category="http://schemas.ogf.org/occi/infrastructure#storagelink";occi.core.id="b2f7f1de-c60c-5b08-879c-81f52429c4ef" occi.core.title="monitoring" occi.storagelink.deviceid="xvda" occi.storagelink.state="inactive" org.opennebula.storagelink.bus="ide" org.opennebula.storagelink.driver="tap2:tapdisk:aio:" Link: </network/e4bd81c4-adda-5626-840d-39bb7959db97>;rel="http://schemas.ogf.org/occi/infrastructure#network";self="/networkinterface/e75ab249-9325-511c-82b8-a7e4430381e3";category="http://schemas.ogf.org/occi/infrastructure#networkinterface";occi.core.id="e75ab249-9325-511c-82b8-a7e4430381e3" occi.core.title="monitoring" occi.networkinterface.address="192.168.254.18" occi.networkinterface.mac="02:00:c0:a8:fe:12" occi.networkinterface.state="inactive" org.opennebula.networkinterface.bridge="xenbr0"|
 
That can be parsed by calling:
 
Occi::Parser.parse('text/plain', compute_text_plain, false, Occi::Core::Resource, {})
 
&hellip;&nbsp;returning a collection of <code>Resource</code> objects (in this case holding one object).
 
 
= Logger =
 
''rOCCI-core'' provides its own logging facility. To initiate logging, one needs to initialize a logger (<code>Occi::Log</code>) instance with the desired output file (either a regular file or an I/O object such as <code>STDOUT</code> or <code>STDERR</code>) and the logging level. The following levels are recognized in an ascending order of severity:
# <code>Occi::Log::DEBUG</code>
# <code>Occi::Log::INFO</code>
# <code>Occi::Log::WARN</code>
# <code>Occi::Log::ERROR</code>
# <code>Occi::Log::FATAL</code>
 
For instance, the following sequence initializes a logger to output messages with level <code>ERROR</code> or higher to <code>STDERR</code>:
 
logger = Occi::Log.new STDERR
logger.level=Occi::Log::ERROR
 
&hellip;&nbsp;while the next one initializes another instance of <code>Occi::Log</code> to write highly verbose debugging output to a regular file:
 
debuglog = Occi::Log.new "/tmp/rOCCI_debug.log"
debuglog.level=Occi::Log::DEBUG
 
 
= Model =
 
An OCCI model reflects the capabilities of a given resource manager. It is used for local discovery and validation of desired actions.
 
In normal conditions, an instance of <code>Occi::Model</code> is created by querying an actual resource provider and parsing its response. For testing, an instance of a model can be set up manually. Note that in real life the contents of <code>mod_response</code> would be passed by the remote side.
 
mod_response = "Category: entity;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Entity\";location=\"/entity/\";attributes=\"occi.core.id occi.core.title\"\nCategory: resource;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Resource\";rel=\"http://schemas.ogf.org/occi/core#entity\";location=\"/resource/\";attributes=\"occi.core.summary\"\nCategory: link;scheme=\"http://schemas.ogf.org/occi/core#\";class=\"kind\";title=\"Link\";rel=\"http://schemas.ogf.org/occi/core#entity\";location=\"/link/\";attributes=\"occi.core.target occi.core.source\"\nCategory: compute;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";title=\"Compute Resource\";rel=\"http://schemas.ogf.org/occi/core#resource\";location=\"/compute/\";attributes=\"occi.compute.architecture occi.compute.cores occi.compute.hostname occi.compute.speed occi.compute.memory occi.compute.state\";actions=\"http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop http://schemas.ogf.org/occi/infrastructure/compute/action#restart http://schemas.ogf.org/occi/infrastructure/compute/action#suspend\"\nCategory: storagelink;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";title=\"Storage Link\";rel=\"http://schemas.ogf.org/occi/core#link\";location=\"/storagelink/\";attributes=\"occi.storagelink.deviceid occi.storagelink.mountpoint occi.storagelink.state\"\nCategory: network;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";title=\"Network Resource\";rel=\"http://schemas.ogf.org/occi/core#resource\";location=\"/network/\";attributes=\"occi.network.vlan occi.network.label occi.network.state\";actions=\"http://schemas.ogf.org/occi/infrastructure/network/action#up http://schemas.ogf.org/occi/infrastructure/network/action#down\"\nCategory: storage;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";title=\"Storage Resource\";rel=\"http://schemas.ogf.org/occi/core#resource\";location=\"/storage/\";attributes=\"occi.storage.size occi.storage.state\";actions=\"http://schemas.ogf.org/occi/infrastructure/storage/action#online http://schemas.ogf.org/occi/infrastructure/storage/action#offline http://schemas.ogf.org/occi/infrastructure/storage/action#backup http://schemas.ogf.org/occi/infrastructure/storage/action#snapshot http://schemas.ogf.org/occi/infrastructure/storage/action#resize\"\nCategory: networkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"kind\";title=\"Networkinterface\";rel=\"http://schemas.ogf.org/occi/core#link\";location=\"/networkinterface/\";attributes=\"occi.networkinterface.interface occi.networkinterface.mac occi.networkinterface.state\"\nCategory: console;scheme=\"http://schemas.ogf.org/occi/infrastructure/compute#\";class=\"kind\";title=\"Link to the VM's console\";rel=\"http://schemas.ogf.org/occi/core#link\";location=\"/console/\"\nCategory: os_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"mixin\";title=\"Operating System Template\";location=\"/mixins/os_tpl/\"\nCategory: ipnetwork;scheme=\"http://schemas.ogf.org/occi/infrastructure/network#\";class=\"mixin\";title=\"IP Network Mixin\";location=\"/mixins/ipnetwork/\";attributes=\"occi.network.address occi.network.gateway occi.network.allocation occi.network.state\"\nCategory: ipnetworkinterface;scheme=\"http://schemas.ogf.org/occi/infrastructure/networkinterface#\";class=\"mixin\";title=\"IP Networkinterface Mixin\";location=\"/mixins/ipnetworkinterface/\";attributes=\"occi.networkinterface.address occi.networkinterface.gateway occi.networkinterface.allocation occi.networkinterface.state\"\nCategory: resource_tpl;scheme=\"http://schemas.ogf.org/occi/infrastructure#\";class=\"mixin\";title=\"Resource Template\";location=\"/mixins/resource_tpl/\"\nCategory: compute;scheme=\"http://opennebula.org/occi/infrastructure#\";class=\"mixin\";title=\"OpenNebula specific Compute attributes\";location=\"/mixins/compute/\";attributes=\"org.opennebula.compute.cpu org.opennebula.compute.kernel org.opennebula.compute.initrd org.opennebula.compute.root org.opennebula.compute.kernel_cmd org.opennebula.compute.bootloader org.opennebula.compute.boot\"\nCategory: storagelink;scheme=\"http://opennebula.org/occi/infrastructure#\";class=\"mixin\";title=\"OpenNebula specific Storagelink attributes\";location=\"/mixins/storagelink/\";attributes=\"org.opennebula.storagelink.bus org.opennebula.storagelink.driver\"\nCategory: network;scheme=\"http://opennebula.org/occi/infrastructure#\";class=\"mixin\";title=\"OpenNebula specific Network attributes\";location=\"/mixins/network/\";attributes=\"org.opennebula.network.id org.opennebula.network.bridge org.opennebula.network.vlan org.opennebula.network.phydev org.opennebula.network.ip_start org.opennebula.network.ip_end\"\nCategory: storage;scheme=\"http://opennebula.org/occi/infrastructure#\";class=\"mixin\";title=\"OpenNebula specific Storage attributes\";location=\"/mixins/storage/\";attributes=\"org.opennebula.storage\"\nCategory: networkinterface;scheme=\"http://opennebula.org/occi/infrastructure#\";class=\"mixin\";title=\"OpenNebula specific Networkinterface attributes\";location=\"/mixins/networkinterface/\";attributes=\"org.opennebula.networkinterface.bridge org.opennebula.networkinterface.script org.opennebula.networkinterface.model org.opennebula.networkinterface.white_ports_tcp org.opennebula.networkinterface.black_ports_tcp org.opennebula.networkinterface.white_ports_udp org.opennebula.networkinterface.black_ports_udp org.opennebula.networkinterface.icmp\"\nCategory: large;scheme=\"https://occi.localhost/occi/infrastructure/resource_tpl#\";class=\"mixin\";title=\"Large Instance - 2 cores and 7.5 GB of RAM\";rel=\"http://schemas.ogf.org/occi/infrastructure#resource_tpl\";location=\"/mixins/large/\";attributes=\"occi.compute.architecture occi.compute.cores occi.compute.speed occi.compute.memory\"\nCategory: extra_large;scheme=\"https://occi.localhost/occi/infrastructure/resource_tpl#\";class=\"mixin\";title=\"Extra Large Instance - 4 cores and 15 GB of RAM\";rel=\"http://schemas.ogf.org/occi/infrastructure#resource_tpl\";location=\"/mixins/extra_large/\";attributes=\"occi.compute.architecture occi.compute.cores occi.compute.speed occi.compute.memory\"\nCategory: larger;scheme=\"https://occi.localhost/occi/infrastructure/resource_tpl#\";class=\"mixin\";title=\"Larger Instance - 4 cores and 10 GB of RAM\";rel=\"http://schemas.ogf.org/occi/infrastructure#resource_tpl\";location=\"/mixins/larger/\";attributes=\"occi.compute.architecture occi.compute.cores occi.compute.speed occi.compute.memory\"\nCategory: medium;scheme=\"https://occi.localhost/occi/infrastructure/resource_tpl#\";class=\"mixin\";title=\"Medium Instance - 2 cores and 3.75 GB of RAM\";rel=\"http://schemas.ogf.org/occi/infrastructure#resource_tpl\";location=\"/mixins/medium/\";attributes=\"occi.compute.architecture occi.compute.cores occi.compute.speed occi.compute.memory\"\nCategory: small;scheme=\"https://occi.localhost/occi/infrastructure/resource_tpl#\";class=\"mixin\";title=\"Small Instance - 1 core and 1.7 GB of RAM\";rel=\"http://schemas.ogf.org/occi/infrastructure#resource_tpl\";location=\"/mixins/small/\";attributes=\"occi.compute.architecture occi.compute.cores occi.compute.speed occi.compute.memory\"\nCategory: monitoring;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"monitoring\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/monitoring/\"\nCategory: debianvm;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"debianvm\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/debianvm/\"\nCategory: egicf2012_demo;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"egicf2012-demo\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/egicf2012_demo/\"\nCategory: oxfordcorpusserver;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"OxfordCorpusServer\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/oxfordcorpusserver/\"\nCategory: omserver;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"OMServer\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/omserver/\"\nCategory: wenmr_demo_rp;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"WeNMR-Demo-CESNET\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/wenmr_demo_rp/\"\nCategory: egi_sl6goldenimage_rp;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"EGI-SL6GoldenImage-CESNET\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/egi_sl6goldenimage_rp/\"\nCategory: hadoop;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"hadoop\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/hadoop/\"\nCategory: clever_unime;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"clever-unime\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/clever_unime/\"\nCategory: generic_vm;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"generic_vm\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/generic_vm/\"\nCategory: octave;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"octave\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/octave/\"\nCategory: r;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"r\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/r/\"\nCategory: egi_compss_rp;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"EGI-COMPSs-CESNET\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/egi_compss_rp/\"\nCategory: esa_sl64_rp;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"ESA-SL64-CESNET\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/esa_sl64_rp/\"\nCategory: generic_www;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"generic_www\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/generic_www/\"\nCategory: egi_compss;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"EGI-COMPSs\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/egi_compss/\"\nCategory: biovel_nfs;scheme=\"https://occi.localhost/occi/infrastructure/os_tpl#\";class=\"mixin\";title=\"biovel_nfs\";rel=\"http://schemas.ogf.org/occi/infrastructure#os_tpl\";location=\"/mixins/biovel_nfs/\"\nCategory: start;scheme=\"http://schemas.ogf.org/occi/infrastructure/compute/action#\";class=\"action\";title=\"Start Compute instance\"\nCategory: stop;scheme=\"http://schemas.ogf.org/occi/infrastructure/compute/action#\";class=\"action\";title=\"Stop Compute instance\";attributes=\"method\"\nCategory: restart;scheme=\"http://schemas.ogf.org/occi/infrastructure/compute/action#\";class=\"action\";title=\"Restart Compute instance\";attributes=\"method\"\nCategory: suspend;scheme=\"http://schemas.ogf.org/occi/infrastructure/compute/action#\";class=\"action\";title=\"Suspend Compute instance\";attributes=\"method\"\nCategory: up;scheme=\"http://schemas.ogf.org/occi/infrastructure/network/action#\";class=\"action\";title=\"Activate network\"\nCategory: down;scheme=\"http://schemas.ogf.org/occi/infrastructure/network/action#up\";class=\"action\";title=\"Activate network\"\nCategory: online;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"action\";title=\"Activate Storage\"\nCategory: offline;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"action\";title=\"Deactivate Storage\"\nCategory: backup;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"action\";title=\"Backup Storage\"\nCategory: snapshot;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"action\";title=\"Snapshot Storage\"\nCategory: resize;scheme=\"http://schemas.ogf.org/occi/infrastructure/storage/action#\";class=\"action\";title=\"Resize Storage\";attributes=\"size\""
collection = Occi::Parser.parse 'text/plain', mod_response, true
model = Occi::Model.new(collection)
 
Then, for instance, to list categories specific to <code>compute</code>:
 
model.get_by_id "http://schemas.ogf.org/occi/infrastructure#compute"
 
= Configuration =
 
The behavior of ''rOCCI-core'' is governed in some respect &ndash; namely where a code change introduced a possibility of backward-incompatible behavior &ndash; by the contents of the configuration file <code>occi.yml</code>

Revision as of 14:46, 11 October 2017

OCCI Classes

This page is no longer maintained. See the-rocci-project/rOCCI-core.