/**
 * Copyright (C) Bosch Sensortec GmbH. All Rights Reserved. Confidential.
 *
 * Disclaimer
 *
 * Common:
 * Bosch Sensortec products are developed for the consumer goods industry. They may only be used
 * within the parameters of the respective valid product data sheet. Bosch Sensortec products are
 * provided with the express understanding that there is no warranty of fitness for a particular purpose.
 * They are not fit for use in life-sustaining, safety or security sensitive systems or any system or device
 * that may lead to bodily harm or property damage if the system or device malfunctions. In addition,
 * Bosch Sensortec products are not fit for use in products which interact with motor vehicle systems.
 * The resale and/or use of products are at the purchaser's own risk and his own responsibility. The
 * examination of fitness for the intended use is the sole responsibility of the Purchaser.
 *
 * The purchaser shall indemnify Bosch Sensortec from all third party claims, including any claims for
 * incidental, or consequential damages, arising from any product use not covered by the parameters of
 * the respective valid product data sheet or not approved by Bosch Sensortec and reimburse Bosch
 * Sensortec for all costs in connection with such claims.
 *
 * The purchaser must monitor the market for the purchased products, particularly with regard to
 * product safety and inform Bosch Sensortec without delay of all security relevant incidents.
 *
 * Engineering Samples are marked with an asterisk (*) or (e). Samples may vary from the valid
 * technical specifications of the product series. They are therefore not intended or fit for resale to third
 * parties or for use in end products. Their sole purpose is internal client testing. The testing of an
 * engineering sample may in no way replace the testing of a product series. Bosch Sensortec
 * assumes no liability for the use of engineering samples. By accepting the engineering samples, the
 * Purchaser agrees to indemnify Bosch Sensortec from all claims arising from the use of engineering
 * samples.
 *
 * Special:
 * This software module (hereinafter called "Software") and any information on application-sheets
 * (hereinafter called "Information") is provided free of charge for the sole purpose to support your
 * application work. The Software and Information is subject to the following terms and conditions:
 *
 * The Software is specifically designed for the exclusive use for Bosch Sensortec products by
 * personnel who have special experience and training. Do not use this Software if you do not have the
 * proper experience or training.
 *
 * This Software package is provided `` as is `` and without any expressed or implied warranties,
 * including without limitation, the implied warranties of merchantability and fitness for a particular
 * purpose.
 *
 * Bosch Sensortec and their representatives and agents deny any liability for the functional impairment
 * of this Software in terms of fitness, performance and safety. Bosch Sensortec and their
 * representatives and agents shall not be liable for any direct or indirect damages or injury, except as
 * otherwise stipulated in mandatory applicable law.
 *
 * The Information provided is believed to be accurate and reliable. Bosch Sensortec assumes no
 * responsibility for the consequences of use of such Information nor for any infringement of patents or
 * other rights of third parties which may result from its use. No license is granted by implication or
 * otherwise under any patent or patent rights of Bosch. Specifications mentioned in the Information are
 * subject to change without notice.
 *
 * It is not allowed to deliver the source code of the Software to any third party without permission of
 * Bosch Sensortec.
 *
 * @file     bsec_interface.h  
 *
 * @brief      
 * Contains the API for BSEC
 *
 */

#ifndef __BSEC_INTERFACE_H__
#define __BSEC_INTERFACE_H__

#include "bsec_datatypes.h"

#ifdef __cplusplus
 extern "C" {
#endif


 /*! @addtogroup bsec_interface BSEC Standard Interfaces
 *   @brief Standard interfaces of BSEC signal processing library. 
 * These interfaces supports in interfacing single BME68x sensor with the BSEC library.
 *
 * ### Interface usage
 * 
 * The following provides a short overview on the typical operation sequence for BSEC.
 * 
 * - Initialization of the library
 * 
 * | Steps                                                               | Function                 |
 * |---------------------------------------------------------------------|--------------------------|
 * | Initialization of library                                           | bsec_init()              |
 * | Update configuration settings (optional)                            | bsec_set_configuration() |
 * | Restore the state of the library (optional)                         | bsec_set_state()         |
 *
 * 
 * - The following function is called to enable output signals and define their sampling rate / operation mode.
 * 
 * | Steps                                       |  Function                  |
 * |---------------------------------------------|----------------------------|
 * | Enable library outputs with specified mode  | bsec_update_subscription() |
 *
 * 
 * - This table describes the main processing loop.
 * 
 * | Steps                                     | Function                         |
 * |-------------------------------------------|----------------------------------|
 * | Retrieve sensor settings to be used       | bsec_sensor_control()            |
 * | Configure sensor and trigger measurement  | [See BME68x API and example codes](https://github.com/BoschSensortec/BME68x-Sensor-API) |
 * | Read results from sensor                  | [See BME68x API and example codes](https://github.com/BoschSensortec/BME68x-Sensor-API) |
 * | Perform signal processing                 | bsec_do_steps()                  |
 *
 * 
 * - Before shutting down the system, the current state of BSEC can be retrieved and can then be used during 
 *   re-initialization to continue processing.
 *   
 * | Steps                                       | Function          |
 * |---------------------------------------------|-------------------|
 * | Retrieve the current library state          |  bsec_get_state() |
 * | Retrieve the current library configuration  |  bsec_get_configuration() |
 * 
 * 
 * ### Configuration and state                       
 * 
 * Values of variables belonging to a BSEC instance are divided into two groups:
 *  - Values **not updated by processing** of signals belong to the **configuration group**. If available, BSEC can be 
 *    configured before use with a customer specific configuration string.
 *  - Values **updated during processing** are member of the **state group**. Saving and restoring of the state of BSEC 
 *    is necessary to maintain previously estimated sensor models and baseline information which is important for best 
 *    performance of the gas sensor outputs.
 * 
 * @note BSEC library consists of adaptive algorithms which models the gas sensor which improves its performance over 
 *       the time. These will be lost if library is initialized due to system reset. In order to avoid this situation 
 *       library state shall be stored in non volatile memory so that it can be loaded after system reset.
 *
 * 
 *   @{
 */


/*!
 * @brief Return the version information of BSEC library
 *
 * @param [out]     bsec_version_p      pointer to struct which is to be populated with the version information
 *
 * @return Zero if successful, otherwise an error code
 *
 * See also: bsec_version_t
 *
  \code{.c}
    // Example // 
    bsec_version_t  version;
    bsec_get_version(&version);
    printf("BSEC version: %d.%d.%d.%d",version.major, version.minor, version.major_bugfix, version.minor_bugfix);
 
  \endcode
*/

bsec_library_return_t bsec_get_version(bsec_version_t * bsec_version_p);


/*!
 * @brief Initialize the library
 *
 * Initialization and reset of BSEC is performed by calling bsec_init(). Calling this function sets up the relation 
 * among all internal modules, initializes run-time dependent library states and resets the configuration and state
 * of all BSEC signal processing modules to defaults.
 * 
 * Before any further use, the library must be initialized. This ensure that all memory and states are in defined
 * conditions prior to processing any data.
 *
 * @return Zero if successful, otherwise an error code
 *
  \code{.c}
 
    // Initialize BSEC library before further use
    bsec_init();

  \endcode
*/

bsec_library_return_t bsec_init(void);

/*!
 * @brief Subscribe to library virtual sensors outputs
 *
 * Use bsec_update_subscription() to instruct BSEC which of the processed output signals are requested at which sample rates.
 * See ::bsec_virtual_sensor_t for available library outputs. 
 *
 * Based on the requested virtual sensors outputs, BSEC will provide information about the required physical sensor input signals 
 * (see ::bsec_physical_sensor_t) with corresponding sample rates. This information is purely informational as bsec_sensor_control()
 * will ensure the sensor is operated in the required manner. To disable a virtual sensor, set the sample rate to ::BSEC_SAMPLE_RATE_DISABLED.
 *
 * The subscription update using bsec_update_subscription() is apart from the signal processing one of the the most 
 * important functions. It allows to enable the desired library outputs. The function determines which physical input 
 * sensor signals are required at which sample rate to produce the virtual output sensor signals requested by the user. 
 * When this function returns with success, the requested outputs are called subscribed. A very important feature is the 
 * retaining of already subscribed outputs. Further outputs can be requested or disabled both individually and 
 * group-wise in addition to already subscribed outputs without changing them unless a change of already subscribed 
 * outputs is requested.
 *
 * @note The state of the library concerning the subscribed outputs cannot be retained among reboots.
 *
 * The interface of bsec_update_subscription() requires the usage of arrays of sensor configuration structures. 
 * Such a structure has the fields sensor identifier and sample rate. These fields have the properties:
 *  - Output signals of virtual sensors must be requested using unique identifiers (Member of ::bsec_virtual_sensor_t)
 *  - Different sets of identifiers are available for inputs of physical sensors and outputs of virtual sensors
 *  - Identifiers are unique values defined by the library, not from external
 *  - Sample rates must be provided as value of
 *     - An allowed sample rate for continuously sampled signals
 *     - 65535.0f (BSEC_SAMPLE_RATE_DISABLED) to turn off outputs and identify disabled inputs
 *
 * @note The same sensor identifiers are also used within the functions bsec_do_steps().
 *
 * The usage principles of bsec_update_subscription() are:
 *  - Differential updates (i.e., only asking for outputs that the user would like to change) is supported.
 *  - Invalid requests of outputs are ignored. Also if one of the requested outputs is unavailable, all the requests 
 *    are ignored. At the same time, a warning is returned.
 *  - To disable BSEC, all outputs shall be turned off. Only enabled (subscribed) outputs have to be disabled while 
 *    already disabled outputs do not have to be disabled explicitly.
 *
 * @param[in]       requested_virtual_sensors       Pointer to array of requested virtual sensor (output) configurations for the library
 * @param[in]       n_requested_virtual_sensors     Number of virtual sensor structs pointed by requested_virtual_sensors
 * @param[out]      required_sensor_settings        Pointer to array of required physical sensor configurations for the library
 * @param[in,out]   n_required_sensor_settings      [in] Size of allocated required_sensor_settings array, [out] number of sensor configurations returned
 *
 * @return Zero when successful, otherwise an error code
 *
 * @sa bsec_sensor_configuration_t
 * @sa bsec_physical_sensor_t
 * @sa bsec_virtual_sensor_t
 *
  \code{.c}
    // Example //

    // Change 3 virtual sensors (switch IAQ and raw temperature -> on / pressure -> off) 
    bsec_sensor_configuration_t requested_virtual_sensors[3];
    uint8_t n_requested_virtual_sensors = 3;
 
    requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
    requested_virtual_sensors[0].sample_rate = BSEC_SAMPLE_RATE_ULP; 
    requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
    requested_virtual_sensors[1].sample_rate = BSEC_SAMPLE_RATE_ULP; 
    requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
    requested_virtual_sensors[2].sample_rate = BSEC_SAMPLE_RATE_DISABLED; 
    
    // Allocate a struct for the returned physical sensor settings
    bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
    uint8_t  n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;
 
    // Call bsec_update_subscription() to enable/disable the requested virtual sensors
    bsec_update_subscription(requested_virtual_sensors, n_requested_virtual_sensors, required_sensor_settings, &n_required_sensor_settings);
  \endcode
 *
 */
bsec_library_return_t bsec_update_subscription(const bsec_sensor_configuration_t * const requested_virtual_sensors,
                const uint8_t n_requested_virtual_sensors, bsec_sensor_configuration_t * required_sensor_settings,
                uint8_t * n_required_sensor_settings);


/*!
 * @brief Main signal processing function of BSEC
 *
 *
 * Processing of the input signals and returning of output samples is performed by bsec_do_steps().
 * - The samples of all library inputs must be passed with unique identifiers representing the input signals from 
 *   physical sensors where the order of these inputs can be chosen arbitrary. However, all input have to be provided 
 *   within the same time period as they are read. A sequential provision to the library might result in undefined 
 *   behavior.
 * - The samples of all library outputs are returned with unique identifiers corresponding to the output signals of 
 *   virtual sensors where the order of the returned outputs may be arbitrary.
 * - The samples of all input as well as output signals of physical as well as virtual sensors use the same 
 *   representation in memory with the following fields:
 * - Sensor identifier:
 *   - For inputs: required to identify the input signal from a physical sensor
 *   - For output: overwritten by bsec_do_steps() to identify the returned signal from a virtual sensor
 *   - Time stamp of the sample
 *
 * Calling bsec_do_steps() requires the samples of the input signals to be provided along with their time stamp when 
 * they are recorded and only when they are acquired. Repetition of samples with the same time stamp are ignored and 
 * result in a warning. Repetition of values of samples which are not acquired anew by a sensor result in deviations 
 * of the computed output signals. Concerning the returned output samples, an important feature is, that a value is 
 * returned for an output only when a new occurrence has been computed. A sample of an output signal is returned only 
 * once.
 *
 *
 * @param[in]       inputs          Array of input data samples. Each array element represents a sample of a different physical sensor.
 * @param[in]       n_inputs        Number of passed input data structs.
 * @param[out]      outputs         Array of output data samples. Each array element represents a sample of a different virtual sensor.
 * @param[in,out]   n_outputs       [in] Number of allocated output structs, [out] number of outputs returned
 *
 * @return Zero when successful, otherwise an error code
 *

 \code{.c}
    // Example //
        
    // Allocate input and output memory
    bsec_input_t input[3];
    uint8_t n_input = 3;
    bsec_output_t output[2];
    uint8_t  n_output=2;

    bsec_library_return_t status;

    // Populate the input structs, assuming the we have timestamp (ts), 
    // gas sensor resistance (R), temperature (T), and humidity (rH) available
    // as input variables
    input[0].sensor_id = BSEC_INPUT_GASRESISTOR;
    input[0].signal = R;
    input[0].time_stamp= ts;   
    input[1].sensor_id = BSEC_INPUT_TEMPERATURE;   
    input[1].signal = T;   
    input[1].time_stamp= ts;   
    input[2].sensor_id = BSEC_INPUT_HUMIDITY;
    input[2].signal = rH;
    input[2].time_stamp= ts;   

        
    // Invoke main processing BSEC function
    status = bsec_do_steps( input, n_input, output, &n_output );

    // Iterate through the BSEC output data, if the call succeeded
    if(status == BSEC_OK)
    {
        for(int i = 0; i < n_output; i++)
        {   
            switch(output[i].sensor_id)
            {
                case BSEC_OUTPUT_IAQ:
                    // Retrieve the IAQ results from output[i].signal
                    // and do something with the data
                    break;
                case BSEC_OUTPUT_STATIC_IAQ:
                    // Retrieve the static IAQ results from output[i].signal
                    // and do something with the data
                    break;
                
            }
        }
    }
    
 \endcode
 */
 
bsec_library_return_t bsec_do_steps(const bsec_input_t * const inputs, const uint8_t n_inputs, bsec_output_t * outputs, uint8_t * n_outputs);


/*!
 * @brief Reset a particular virtual sensor output
 *
 * This function allows specific virtual sensor outputs to be reset. The meaning of "reset" depends on the specific 
 * output. In case of the IAQ output, reset means zeroing the output to the current ambient conditions.
 *
 * @param[in]       sensor_id           Virtual sensor to be reset
 *
 * @return Zero when successful, otherwise an error code
 *
 *
  \code{.c}
    // Example // 
    bsec_reset_output(BSEC_OUTPUT_IAQ);

  \endcode
 */

bsec_library_return_t bsec_reset_output(uint8_t sensor_id);


/*!
 * @brief Update algorithm configuration parameters
 *
 * BSEC uses a default configuration for the modules and common settings. The initial configuration can be customized 
 * by bsec_set_configuration(). This is an optional step.
 * 
 * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose 
 * the serialization and apply it to the library and its modules.
 *
 * Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size.
 *
 * @param[in]       serialized_settings     Settings serialized to a binary blob
 * @param[in]       n_serialized_settings   Size of the settings blob
 * @param[in,out]   work_buffer             Work buffer used to parse the blob
 * @param[in]       n_work_buffer_size      Length of the work buffer available for parsing the blob
 *
 * @return Zero when successful, otherwise an error code
 *
  \code{.c}
    // Example // 
    
    // Allocate variables
    uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE];
    uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE;
    uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
    uint32_t n_work_buffer = BSEC_MAX_WORKBUFFER_SIZE;

    // Here we will load a provided config string into serialized_settings 
    
    // Apply the configuration
    bsec_set_configuration(serialized_settings, n_serialized_settings_max, work_buffer, n_work_buffer);

  \endcode
 */

bsec_library_return_t bsec_set_configuration(const uint8_t * const serialized_settings,
                const uint32_t n_serialized_settings, uint8_t * work_buffer,
                const uint32_t n_work_buffer_size);


/*!
 * @brief Restore the internal state of the library
 *
 * BSEC uses a default state for all signal processing modules and the BSEC module. To ensure optimal performance, 
 * especially of the gas sensor functionality, it is recommended to retrieve the state using bsec_get_state()
 * before unloading the library, storing it in some form of non-volatile memory, and setting it using bsec_set_state() 
 * before resuming further operation of the library.
 * 
 * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the 
 * serialization and apply it to the library and its modules.
 *
 * Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size.
 *
 * @param[in]       serialized_state        States serialized to a binary blob
 * @param[in]       n_serialized_state      Size of the state blob
 * @param[in,out]   work_buffer             Work buffer used to parse the blob
 * @param[in]       n_work_buffer_size      Length of the work buffer available for parsing the blob
 *
 * @return Zero when successful, otherwise an error code
 *
  \code{.c}
    // Example // 
  
    // Allocate variables
    uint8_t serialized_state[BSEC_MAX_PROPERTY_BLOB_SIZE];
    uint32_t  n_serialized_state = BSEC_MAX_PROPERTY_BLOB_SIZE;
    uint8_t work_buffer_state[BSEC_MAX_WORKBUFFER_SIZE];
    uint32_t  n_work_buffer_size = BSEC_MAX_WORKBUFFER_SIZE;

    // Here we will load a state string from a previous use of BSEC

    // Apply the previous state to the current BSEC session
    bsec_set_state(serialized_state, n_serialized_state, work_buffer_state, n_work_buffer_size);

  \endcode
*/

bsec_library_return_t bsec_set_state(const uint8_t * const serialized_state, const uint32_t n_serialized_state,
                uint8_t * work_buffer, const uint32_t n_work_buffer_size);


/*!
 * @brief Retrieve the current library configuration
 *
 * BSEC allows to retrieve the current configuration using bsec_get_configuration(). Returns a binary blob encoding 
 * the current configuration parameters of the library in a format compatible with bsec_set_configuration().
 *
 * @note The function bsec_get_configuration() is required to be used for debugging purposes only.
 * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the 
 * serialization and apply it to the library and its modules.
 *
 * Please use #BSEC_MAX_PROPERTY_BLOB_SIZE for allotting the required size.
 * 
 * @param[in]       config_id                   Identifier for a specific set of configuration settings to be returned;
 *                                              shall be zero to retrieve all configuration settings.
 * @param[out]      serialized_settings         Buffer to hold the serialized config blob
 * @param[in]       n_serialized_settings_max   Maximum available size for the serialized settings
 * @param[in,out]   work_buffer                 Work buffer used to parse the binary blob
 * @param[in]       n_work_buffer               Length of the work buffer available for parsing the blob
 * @param[out]      n_serialized_settings       Actual size of the returned serialized configuration blob
 *
 * @return Zero when successful, otherwise an error code
 *
  \code{.c}
    // Example //
 
    // Allocate variables
    uint8_t serialized_settings[BSEC_MAX_PROPERTY_BLOB_SIZE];
    uint32_t n_serialized_settings_max = BSEC_MAX_PROPERTY_BLOB_SIZE;
    uint8_t work_buffer[BSEC_MAX_WORKBUFFER_SIZE];
    uint32_t n_work_buffer = BSEC_MAX_WORKBUFFER_SIZE;
    uint32_t n_serialized_settings = 0;
    
    // Configuration of BSEC algorithm is stored in 'serialized_settings'
    bsec_get_configuration(0, serialized_settings, n_serialized_settings_max, work_buffer, n_work_buffer, &n_serialized_settings);

  \endcode
 */

bsec_library_return_t bsec_get_configuration(const uint8_t config_id, uint8_t * serialized_settings, const uint32_t n_serialized_settings_max,
                uint8_t * work_buffer, const uint32_t n_work_buffer, uint32_t * n_serialized_settings);


/*!
 *@brief Retrieve the current internal library state
 *
 * BSEC allows to retrieve the current states of all signal processing modules and the BSEC module using 
 * bsec_get_state(). This allows a restart of the processing after a reboot of the system by calling bsec_set_state().
 * 
 * @note A work buffer with sufficient size is required and has to be provided by the function caller to decompose the 
 * serialization and apply it to the library and its modules.
 *
 * Please use #BSEC_MAX_STATE_BLOB_SIZE for allotting the required size.
 * 
 * @param[in]       state_set_id                Identifier for a specific set of states to be returned; shall be
 *                                              zero to retrieve all states.
 * @param[out]      serialized_state            Buffer to hold the serialized config blob
 * @param[in]       n_serialized_state_max      Maximum available size for the serialized states
 * @param[in,out]   work_buffer                 Work buffer used to parse the blob
 * @param[in]       n_work_buffer               Length of the work buffer available for parsing the blob
 * @param[out]      n_serialized_state          Actual size of the returned serialized blob
 *
 * @return Zero when successful, otherwise an error code
 *
  \code{.c}
    // Example //
 
    // Allocate variables
    uint8_t serialized_state[BSEC_MAX_STATE_BLOB_SIZE];
    uint32_t n_serialized_state_max = BSEC_MAX_STATE_BLOB_SIZE;
    uint32_t  n_serialized_state = BSEC_MAX_STATE_BLOB_SIZE;
    uint8_t work_buffer_state[BSEC_MAX_WORKBUFFER_SIZE];
    uint32_t  n_work_buffer_size = BSEC_MAX_WORKBUFFER_SIZE;
    
    // Algorithm state is stored in 'serialized_state'
    bsec_get_state(0, serialized_state, n_serialized_state_max, work_buffer_state, n_work_buffer_size, &n_serialized_state);

  \endcode
 */

bsec_library_return_t bsec_get_state(const uint8_t state_set_id, uint8_t * serialized_state,
                const uint32_t n_serialized_state_max, uint8_t * work_buffer, const uint32_t n_work_buffer,
                uint32_t * n_serialized_state);

/*!
 * @brief Retrieve BMExxx sensor instructions
 *
 * The bsec_sensor_control() interface is a key feature of BSEC, as it allows an easy way for the signal processing 
 * library to control the operation of the BME sensor. This is important since gas sensor behaviour is mainly 
 * determined by how the integrated heater is configured. To ensure an easy integration of BSEC into any system, 
 * bsec_sensor_control() will provide the caller with information about the current sensor configuration that is 
 * necessary to fulfill the input requirements derived from the current outputs requested via 
 * bsec_update_subscription().
 *
 * In practice the use of this function shall be as follows:
 * - Call bsec_sensor_control() which returns a bsec_bme_settings_t struct.
 * - Based on the information contained in this struct, the sensor is configured and a forced-mode measurement is 
 *   triggered if requested by bsec_sensor_control().
 * - Once this forced-mode measurement is complete, the signals specified in this struct shall be passed to 
 *   bsec_do_steps() to perform the signal processing.
 * - After processing, the process should sleep until the bsec_bme_settings_t::next_call timestamp is reached.
 *
 * 
 * @param [in]      time_stamp                Current timestamp in [ns]
 * @param[out]      sensor_settings           Settings to be passed to API to operate sensor at this time instance
 *
 * @return Zero when successful, otherwise an error code
 */

bsec_library_return_t bsec_sensor_control(const int64_t time_stamp, bsec_bme_settings_t *sensor_settings);

/*@}*/  //BSEC Interface

#ifdef __cplusplus
 }
#endif

#endif /* __BSEC_INTERFACE_H__ */
