Basic Suunto EON Steel downloading copied from my test application. This parses all the core dive data, including sample data (time, depth, cylinder pressure, deco information etc). The deco information returns ceiling and TTS rather than ceiling and "time at ceiling", because that's what the dive computer has, and I don't see any other way to return the information. We don't report any events yet, though. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
354 lines
14 KiB
C
354 lines
14 KiB
C
/*
|
|
* libdivecomputer
|
|
*
|
|
* Copyright (C) 2012 Jef Driesen
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301 USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <libdivecomputer/descriptor.h>
|
|
|
|
#include "iterator-private.h"
|
|
|
|
#define C_ARRAY_SIZE(array) (sizeof (array) / sizeof *(array))
|
|
|
|
struct dc_descriptor_t {
|
|
const char *vendor;
|
|
const char *product;
|
|
dc_family_t type;
|
|
unsigned int model;
|
|
};
|
|
|
|
/*
|
|
* The model numbers in the table are the actual model numbers reported by the
|
|
* device. For devices where there is no model number available (or known), an
|
|
* artifical number (starting at zero) is assigned. If the model number isn't
|
|
* actually used to identify individual models, identical values are assigned.
|
|
*/
|
|
|
|
static const dc_descriptor_t g_descriptors[] = {
|
|
/* Suunto Solution */
|
|
{"Suunto", "Solution", DC_FAMILY_SUUNTO_SOLUTION, 0},
|
|
/* Suunto Eon */
|
|
{"Suunto", "Eon", DC_FAMILY_SUUNTO_EON, 0},
|
|
{"Suunto", "Solution Alpha", DC_FAMILY_SUUNTO_EON, 0},
|
|
{"Suunto", "Solution Nitrox", DC_FAMILY_SUUNTO_EON, 0},
|
|
/* Suunto Vyper */
|
|
{"Suunto", "Spyder", DC_FAMILY_SUUNTO_VYPER, 0x01},
|
|
{"Suunto", "Stinger", DC_FAMILY_SUUNTO_VYPER, 0x03},
|
|
{"Suunto", "Mosquito", DC_FAMILY_SUUNTO_VYPER, 0x04},
|
|
{"Suunto", "D3", DC_FAMILY_SUUNTO_VYPER, 0x05},
|
|
{"Suunto", "Vyper", DC_FAMILY_SUUNTO_VYPER, 0x0A},
|
|
{"Suunto", "Vytec", DC_FAMILY_SUUNTO_VYPER, 0X0B},
|
|
{"Suunto", "Cobra", DC_FAMILY_SUUNTO_VYPER, 0X0C},
|
|
{"Suunto", "Gekko", DC_FAMILY_SUUNTO_VYPER, 0X0D},
|
|
{"Suunto", "Zoop", DC_FAMILY_SUUNTO_VYPER, 0x16},
|
|
/* Suunto Vyper 2 */
|
|
{"Suunto", "Vyper 2", DC_FAMILY_SUUNTO_VYPER2, 0x10},
|
|
{"Suunto", "Cobra 2", DC_FAMILY_SUUNTO_VYPER2, 0x11},
|
|
{"Suunto", "Vyper Air", DC_FAMILY_SUUNTO_VYPER2, 0x13},
|
|
{"Suunto", "Cobra 3", DC_FAMILY_SUUNTO_VYPER2, 0x14},
|
|
{"Suunto", "HelO2", DC_FAMILY_SUUNTO_VYPER2, 0x15},
|
|
/* Suunto D9 */
|
|
{"Suunto", "D9", DC_FAMILY_SUUNTO_D9, 0x0E},
|
|
{"Suunto", "D6", DC_FAMILY_SUUNTO_D9, 0x0F},
|
|
{"Suunto", "D4", DC_FAMILY_SUUNTO_D9, 0x12},
|
|
{"Suunto", "D4i", DC_FAMILY_SUUNTO_D9, 0x19},
|
|
{"Suunto", "D6i", DC_FAMILY_SUUNTO_D9, 0x1A},
|
|
{"Suunto", "D9tx", DC_FAMILY_SUUNTO_D9, 0x1B},
|
|
{"Suunto", "DX", DC_FAMILY_SUUNTO_D9, 0x1C},
|
|
/* Suunto EON Steel */
|
|
#ifdef HAVE_LIBUSB
|
|
{"Suunto", "EON Steel", DC_FAMILY_SUUNTO_EONSTEEL, 0},
|
|
#endif
|
|
/* Uwatec Aladin */
|
|
{"Uwatec", "Aladin Air Twin", DC_FAMILY_UWATEC_ALADIN, 0x1C},
|
|
{"Uwatec", "Aladin Sport Plus", DC_FAMILY_UWATEC_ALADIN, 0x3E},
|
|
{"Uwatec", "Aladin Pro", DC_FAMILY_UWATEC_ALADIN, 0x3F},
|
|
{"Uwatec", "Aladin Air Z", DC_FAMILY_UWATEC_ALADIN, 0x44},
|
|
{"Uwatec", "Aladin Air Z O2", DC_FAMILY_UWATEC_ALADIN, 0xA4},
|
|
{"Uwatec", "Aladin Air Z Nitrox", DC_FAMILY_UWATEC_ALADIN, 0xF4},
|
|
{"Uwatec", "Aladin Pro Ultra", DC_FAMILY_UWATEC_ALADIN, 0xFF},
|
|
/* Uwatec Memomouse */
|
|
{"Uwatec", "Memomouse", DC_FAMILY_UWATEC_MEMOMOUSE, 0},
|
|
/* Uwatec Smart */
|
|
#ifdef HAVE_IRDA
|
|
{"Uwatec", "Smart Pro", DC_FAMILY_UWATEC_SMART, 0x10},
|
|
{"Uwatec", "Galileo Sol", DC_FAMILY_UWATEC_SMART, 0x11},
|
|
{"Uwatec", "Galileo Luna", DC_FAMILY_UWATEC_SMART, 0x11},
|
|
{"Uwatec", "Galileo Terra", DC_FAMILY_UWATEC_SMART, 0x11},
|
|
{"Uwatec", "Aladin Tec", DC_FAMILY_UWATEC_SMART, 0x12},
|
|
{"Uwatec", "Aladin Prime", DC_FAMILY_UWATEC_SMART, 0x12},
|
|
{"Uwatec", "Aladin Tec 2G", DC_FAMILY_UWATEC_SMART, 0x13},
|
|
{"Uwatec", "Aladin 2G", DC_FAMILY_UWATEC_SMART, 0x13},
|
|
{"Subgear","XP-10", DC_FAMILY_UWATEC_SMART, 0x13},
|
|
{"Uwatec", "Smart Com", DC_FAMILY_UWATEC_SMART, 0x14},
|
|
{"Uwatec", "Aladin 2G", DC_FAMILY_UWATEC_SMART, 0x15},
|
|
{"Subgear","XP-3G", DC_FAMILY_UWATEC_SMART, 0x15},
|
|
{"Uwatec", "Smart Tec", DC_FAMILY_UWATEC_SMART, 0x18},
|
|
{"Uwatec", "Galileo Trimix",DC_FAMILY_UWATEC_SMART, 0x19},
|
|
{"Uwatec", "Smart Z", DC_FAMILY_UWATEC_SMART, 0x1C},
|
|
{"Subgear","XP Air", DC_FAMILY_UWATEC_SMART, 0x1C},
|
|
#endif
|
|
/* Scubapro/Uwatec Meridian */
|
|
{"Scubapro", "Meridian", DC_FAMILY_UWATEC_MERIDIAN, 0x20},
|
|
/* Reefnet */
|
|
{"Reefnet", "Sensus", DC_FAMILY_REEFNET_SENSUS, 1},
|
|
{"Reefnet", "Sensus Pro", DC_FAMILY_REEFNET_SENSUSPRO, 2},
|
|
{"Reefnet", "Sensus Ultra", DC_FAMILY_REEFNET_SENSUSULTRA, 3},
|
|
/* Oceanic VT Pro */
|
|
{"Oceanic", "Versa Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4155},
|
|
{"Aeris", "Atmos 2", DC_FAMILY_OCEANIC_VTPRO, 0x4158},
|
|
{"Oceanic", "Pro Plus 2", DC_FAMILY_OCEANIC_VTPRO, 0x4159},
|
|
{"Aeris", "Atmos AI", DC_FAMILY_OCEANIC_VTPRO, 0x4244},
|
|
{"Oceanic", "VT Pro", DC_FAMILY_OCEANIC_VTPRO, 0x4245},
|
|
{"Sherwood", "Wisdom", DC_FAMILY_OCEANIC_VTPRO, 0x4246},
|
|
{"Aeris", "Elite", DC_FAMILY_OCEANIC_VTPRO, 0x424F},
|
|
/* Oceanic Veo 250 */
|
|
{"Genesis", "React Pro", DC_FAMILY_OCEANIC_VEO250, 0x4247},
|
|
{"Oceanic", "Veo 200", DC_FAMILY_OCEANIC_VEO250, 0x424B},
|
|
{"Oceanic", "Veo 250", DC_FAMILY_OCEANIC_VEO250, 0x424C},
|
|
{"Seemann", "XP5", DC_FAMILY_OCEANIC_VEO250, 0x4251},
|
|
{"Oceanic", "Veo 180", DC_FAMILY_OCEANIC_VEO250, 0x4252},
|
|
{"Aeris", "XR-2", DC_FAMILY_OCEANIC_VEO250, 0x4255},
|
|
{"Sherwood", "Insight", DC_FAMILY_OCEANIC_VEO250, 0x425A},
|
|
/* Oceanic Atom 2.0 */
|
|
{"Oceanic", "Atom 1.0", DC_FAMILY_OCEANIC_ATOM2, 0x4250},
|
|
{"Aeris", "Epic", DC_FAMILY_OCEANIC_ATOM2, 0x4257},
|
|
{"Oceanic", "VT3", DC_FAMILY_OCEANIC_ATOM2, 0x4258},
|
|
{"Aeris", "Elite T3", DC_FAMILY_OCEANIC_ATOM2, 0x4259},
|
|
{"Oceanic", "Atom 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4342},
|
|
{"Oceanic", "Geo", DC_FAMILY_OCEANIC_ATOM2, 0x4344},
|
|
{"Aeris", "Manta", DC_FAMILY_OCEANIC_ATOM2, 0x4345},
|
|
{"Aeris", "XR-1 NX", DC_FAMILY_OCEANIC_ATOM2, 0x4346},
|
|
{"Oceanic", "Datamask", DC_FAMILY_OCEANIC_ATOM2, 0x4347},
|
|
{"Aeris", "Compumask", DC_FAMILY_OCEANIC_ATOM2, 0x4348},
|
|
{"Aeris", "F10", DC_FAMILY_OCEANIC_ATOM2, 0x434D},
|
|
{"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x434E},
|
|
{"Sherwood", "Wisdom 2", DC_FAMILY_OCEANIC_ATOM2, 0x4350},
|
|
{"Sherwood", "Insight 2", DC_FAMILY_OCEANIC_ATOM2, 0x4353},
|
|
{"Genesis", "React Pro White", DC_FAMILY_OCEANIC_ATOM2, 0x4354},
|
|
{"Tusa", "Element II (IQ-750)", DC_FAMILY_OCEANIC_ATOM2, 0x4357},
|
|
{"Oceanic", "Veo 1.0", DC_FAMILY_OCEANIC_ATOM2, 0x4358},
|
|
{"Oceanic", "Veo 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4359},
|
|
{"Oceanic", "Veo 3.0", DC_FAMILY_OCEANIC_ATOM2, 0x435A},
|
|
{"Tusa", "Zen (IQ-900)", DC_FAMILY_OCEANIC_ATOM2, 0x4441},
|
|
{"Tusa", "Zen Air (IQ-950)", DC_FAMILY_OCEANIC_ATOM2, 0x4442},
|
|
{"Aeris", "Atmos AI 2", DC_FAMILY_OCEANIC_ATOM2, 0x4443},
|
|
{"Oceanic", "Pro Plus 2.1", DC_FAMILY_OCEANIC_ATOM2, 0x4444},
|
|
{"Oceanic", "Geo 2.0", DC_FAMILY_OCEANIC_ATOM2, 0x4446},
|
|
{"Oceanic", "VT4", DC_FAMILY_OCEANIC_ATOM2, 0x4447},
|
|
{"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x4449},
|
|
{"Beuchat", "Voyager 2G", DC_FAMILY_OCEANIC_ATOM2, 0x444B},
|
|
{"Oceanic", "Atom 3.0", DC_FAMILY_OCEANIC_ATOM2, 0x444C},
|
|
{"Hollis", "DG03", DC_FAMILY_OCEANIC_ATOM2, 0x444D},
|
|
{"Oceanic", "OCS", DC_FAMILY_OCEANIC_ATOM2, 0x4450},
|
|
{"Oceanic", "OC1", DC_FAMILY_OCEANIC_ATOM2, 0x4451},
|
|
{"Oceanic", "VT 4.1", DC_FAMILY_OCEANIC_ATOM2, 0x4452},
|
|
{"Aeris", "Epic", DC_FAMILY_OCEANIC_ATOM2, 0x4453},
|
|
{"Aeris", "Elite T3", DC_FAMILY_OCEANIC_ATOM2, 0x4455},
|
|
{"Oceanic", "Atom 3.1", DC_FAMILY_OCEANIC_ATOM2, 0x4456},
|
|
{"Aeris", "A300 AI", DC_FAMILY_OCEANIC_ATOM2, 0x4457},
|
|
{"Sherwood", "Wisdom 3", DC_FAMILY_OCEANIC_ATOM2, 0x4458},
|
|
{"Aeris", "A300", DC_FAMILY_OCEANIC_ATOM2, 0x445A},
|
|
{"Hollis", "TX1", DC_FAMILY_OCEANIC_ATOM2, 0x4542},
|
|
{"Sherwood", "Amphos", DC_FAMILY_OCEANIC_ATOM2, 0x4545},
|
|
{"Oceanic", "Pro Plus 3", DC_FAMILY_OCEANIC_ATOM2, 0x4548},
|
|
{"Aeris", "F11", DC_FAMILY_OCEANIC_ATOM2, 0x4549},
|
|
{"Oceanic", "OCi", DC_FAMILY_OCEANIC_ATOM2, 0x454B},
|
|
{"Aeris", "A300CS", DC_FAMILY_OCEANIC_ATOM2, 0x454C},
|
|
/* Mares Nemo */
|
|
{"Mares", "Nemo", DC_FAMILY_MARES_NEMO, 0},
|
|
{"Mares", "Nemo Steel", DC_FAMILY_MARES_NEMO, 0},
|
|
{"Mares", "Nemo Titanium",DC_FAMILY_MARES_NEMO, 0},
|
|
{"Mares", "Nemo Excel", DC_FAMILY_MARES_NEMO, 17},
|
|
{"Mares", "Nemo Apneist", DC_FAMILY_MARES_NEMO, 18},
|
|
/* Mares Puck */
|
|
{"Mares", "Puck", DC_FAMILY_MARES_PUCK, 7},
|
|
{"Mares", "Puck Air", DC_FAMILY_MARES_PUCK, 19},
|
|
{"Mares", "Nemo Air", DC_FAMILY_MARES_PUCK, 4},
|
|
{"Mares", "Nemo Wide", DC_FAMILY_MARES_PUCK, 1},
|
|
/* Mares Darwin */
|
|
{"Mares", "Darwin", DC_FAMILY_MARES_DARWIN , 0},
|
|
{"Mares", "M1", DC_FAMILY_MARES_DARWIN , 0},
|
|
{"Mares", "M2", DC_FAMILY_MARES_DARWIN , 0},
|
|
{"Mares", "Darwin Air", DC_FAMILY_MARES_DARWIN , 1},
|
|
{"Mares", "Airlab", DC_FAMILY_MARES_DARWIN , 1},
|
|
/* Mares Icon HD */
|
|
{"Mares", "Matrix", DC_FAMILY_MARES_ICONHD , 0x0F},
|
|
{"Mares", "Icon HD", DC_FAMILY_MARES_ICONHD , 0x14},
|
|
{"Mares", "Icon HD Net Ready", DC_FAMILY_MARES_ICONHD , 0x15},
|
|
{"Mares", "Puck Pro", DC_FAMILY_MARES_ICONHD , 0x18},
|
|
{"Mares", "Nemo Wide 2", DC_FAMILY_MARES_ICONHD , 0x19},
|
|
{"Mares", "Puck 2", DC_FAMILY_MARES_ICONHD , 0x1F},
|
|
/* Heinrichs Weikamp */
|
|
{"Heinrichs Weikamp", "OSTC", DC_FAMILY_HW_OSTC, 0},
|
|
{"Heinrichs Weikamp", "OSTC Mk2", DC_FAMILY_HW_OSTC, 1},
|
|
{"Heinrichs Weikamp", "OSTC 2N", DC_FAMILY_HW_OSTC, 2},
|
|
{"Heinrichs Weikamp", "OSTC 2C", DC_FAMILY_HW_OSTC, 3},
|
|
{"Heinrichs Weikamp", "Frog", DC_FAMILY_HW_FROG, 0},
|
|
{"Heinrichs Weikamp", "OSTC 3", DC_FAMILY_HW_OSTC3, 0},
|
|
{"Heinrichs Weikamp", "OSTC Sport", DC_FAMILY_HW_OSTC3, 1},
|
|
/* Cressi Edy */
|
|
{"Cressi", "Edy", DC_FAMILY_CRESSI_EDY, 0},
|
|
/* Cressi Leonardo */
|
|
{"Cressi", "Leonardo", DC_FAMILY_CRESSI_LEONARDO, 1},
|
|
{"Cressi", "Giotto", DC_FAMILY_CRESSI_LEONARDO, 4},
|
|
/* Zeagle N2iTiON3 */
|
|
{"Zeagle", "N2iTiON3", DC_FAMILY_ZEAGLE_N2ITION3, 0},
|
|
{"Apeks", "Quantum X", DC_FAMILY_ZEAGLE_N2ITION3, 0},
|
|
{"Dive Rite", "NiTek Trio", DC_FAMILY_ZEAGLE_N2ITION3, 0},
|
|
{"Scubapro", "XTender 5", DC_FAMILY_ZEAGLE_N2ITION3, 0},
|
|
/* Atomic Aquatics Cobalt */
|
|
#ifdef HAVE_LIBUSB
|
|
{"Atomic Aquatics", "Cobalt", DC_FAMILY_ATOMICS_COBALT, 0},
|
|
{"Atomic Aquatics", "Cobalt 2", DC_FAMILY_ATOMICS_COBALT, 2},
|
|
#endif
|
|
/* Shearwater Predator */
|
|
{"Shearwater", "Predator", DC_FAMILY_SHEARWATER_PREDATOR, 2},
|
|
/* Shearwater Petrel */
|
|
{"Shearwater", "Petrel", DC_FAMILY_SHEARWATER_PETREL, 3},
|
|
/* Dive Rite NiTek Q */
|
|
{"Dive Rite", "NiTek Q", DC_FAMILY_DIVERITE_NITEKQ, 0},
|
|
};
|
|
|
|
typedef struct dc_descriptor_iterator_t {
|
|
dc_iterator_t base;
|
|
size_t current;
|
|
} dc_descriptor_iterator_t;
|
|
|
|
static dc_status_t dc_descriptor_iterator_next (dc_iterator_t *iterator, void *item);
|
|
static dc_status_t dc_descriptor_iterator_free (dc_iterator_t *iterator);
|
|
|
|
static const dc_iterator_vtable_t dc_descriptor_iterator_vtable = {
|
|
dc_descriptor_iterator_free,
|
|
dc_descriptor_iterator_next
|
|
};
|
|
|
|
dc_status_t
|
|
dc_descriptor_iterator (dc_iterator_t **out)
|
|
{
|
|
dc_descriptor_iterator_t *iterator = NULL;
|
|
|
|
if (out == NULL)
|
|
return DC_STATUS_INVALIDARGS;
|
|
|
|
iterator = (dc_descriptor_iterator_t *) malloc (sizeof (dc_descriptor_iterator_t));
|
|
if (iterator == NULL)
|
|
return DC_STATUS_NOMEMORY;
|
|
|
|
iterator->base.vtable = &dc_descriptor_iterator_vtable;
|
|
iterator->current = 0;
|
|
|
|
*out = (dc_iterator_t *) iterator;
|
|
|
|
return DC_STATUS_SUCCESS;
|
|
}
|
|
|
|
static dc_status_t
|
|
dc_descriptor_iterator_free (dc_iterator_t *iterator)
|
|
{
|
|
free (iterator);
|
|
|
|
return DC_STATUS_SUCCESS;
|
|
}
|
|
|
|
static dc_status_t
|
|
dc_descriptor_iterator_next (dc_iterator_t *abstract, void *out)
|
|
{
|
|
dc_descriptor_iterator_t *iterator = (dc_descriptor_iterator_t *) abstract;
|
|
dc_descriptor_t **item = (dc_descriptor_t **) out;
|
|
|
|
if (iterator->current >= C_ARRAY_SIZE (g_descriptors))
|
|
return DC_STATUS_DONE;
|
|
|
|
/*
|
|
* The explicit cast from a const to a non-const pointer is safe here. The
|
|
* public interface doesn't support write access, and therefore descriptor
|
|
* objects are always read-only. However, the cast allows to return a direct
|
|
* reference to the entries in the table, avoiding the overhead of
|
|
* allocating (and freeing) memory for a deep copy.
|
|
*/
|
|
*item = (dc_descriptor_t *) &g_descriptors[iterator->current++];
|
|
|
|
return DC_STATUS_SUCCESS;
|
|
}
|
|
|
|
void
|
|
dc_descriptor_free (dc_descriptor_t *descriptor)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const char *
|
|
dc_descriptor_get_vendor (dc_descriptor_t *descriptor)
|
|
{
|
|
if (descriptor == NULL)
|
|
return NULL;
|
|
|
|
return descriptor->vendor;
|
|
}
|
|
|
|
const char *
|
|
dc_descriptor_get_product (dc_descriptor_t *descriptor)
|
|
{
|
|
if (descriptor == NULL)
|
|
return NULL;
|
|
|
|
return descriptor->product;
|
|
}
|
|
|
|
dc_family_t
|
|
dc_descriptor_get_type (dc_descriptor_t *descriptor)
|
|
{
|
|
if (descriptor == NULL)
|
|
return DC_FAMILY_NULL;
|
|
|
|
return descriptor->type;
|
|
}
|
|
|
|
unsigned int
|
|
dc_descriptor_get_model (dc_descriptor_t *descriptor)
|
|
{
|
|
if (descriptor == NULL)
|
|
return 0;
|
|
|
|
return descriptor->model;
|
|
}
|
|
|
|
dc_transport_t
|
|
dc_descriptor_get_transport (dc_descriptor_t *descriptor)
|
|
{
|
|
if (descriptor == NULL)
|
|
return DC_TRANSPORT_NONE;
|
|
|
|
if (descriptor->type == DC_FAMILY_ATOMICS_COBALT)
|
|
return DC_TRANSPORT_USB;
|
|
else if (descriptor->type == DC_FAMILY_SUUNTO_EONSTEEL)
|
|
return DC_TRANSPORT_USB;
|
|
else if (descriptor->type == DC_FAMILY_UWATEC_SMART)
|
|
return DC_TRANSPORT_IRDA;
|
|
else
|
|
return DC_TRANSPORT_SERIAL;
|
|
}
|