Simulated product dispenser

Dependencies:   HTS221

Fork of mbed-cloud-workshop-connect-HTS221 by Jim Carver

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mbase.h Source File

m2mbase.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #ifndef M2M_BASE_H
00017 #define M2M_BASE_H
00018 
00019 // Support for std args
00020 #include <stdint.h>
00021 #include "mbed-client/m2mconfig.h"
00022 #include "mbed-client/m2mreportobserver.h"
00023 #include "mbed-client/functionpointer.h"
00024 #include "mbed-client/m2mstringbuffer.h"
00025 #include "nsdl-c/sn_nsdl.h"
00026 #include "sn_coap_header.h"
00027 #include "nsdl-c/sn_nsdl_lib.h"
00028 
00029 //FORWARD DECLARATION
00030 struct sn_coap_hdr_;
00031 typedef sn_coap_hdr_ sn_coap_hdr_s;
00032 struct nsdl_s;
00033 struct sn_nsdl_addr_;
00034 typedef sn_nsdl_addr_ sn_nsdl_addr_s;
00035 
00036 typedef FP1<void, const char*> value_updated_callback;
00037 typedef void(*value_updated_callback2) (const char* object_name);
00038 class M2MObservationHandler;
00039 class M2MReportHandler;
00040 
00041 class M2MObjectInstance;
00042 class M2MObject;
00043 class M2MResource;
00044 class M2MEndpoint;
00045 
00046 
00047 /*! \file m2mbase.h
00048  *  \brief M2MBase.
00049  *  This class is the base class based on which all LWM2M object models
00050  *  can be created. This serves base class for Object, ObjectInstances and Resources.
00051  */
00052 class M2MBase : public M2MReportObserver {
00053 
00054 public:
00055 
00056     /**
00057       * Enum to define the type of object.
00058       */
00059     typedef enum {
00060         Object = 0x0,
00061         Resource = 0x1,
00062         ObjectInstance = 0x2,
00063         ResourceInstance = 0x3
00064 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
00065         ,ObjectDirectory = 0x4
00066 #endif
00067     } BaseType;
00068 
00069     /**
00070       * Enum to define observation level.
00071       */
00072     typedef enum {
00073         None                 = 0x0,
00074         R_Attribute          = 0x01,
00075         OI_Attribute         = 0x02,
00076         OIR_Attribute        = 0x03,
00077         O_Attribute          = 0x04,
00078         OR_Attribute         = 0x05,
00079         OOI_Attribute        = 0x06,
00080         OOIR_Attribute       = 0x07
00081     } Observation;
00082 
00083 
00084     /**
00085      * \brief Enum defining a resource type.
00086     */
00087     typedef enum {
00088         Static,
00089         Dynamic,
00090         Directory
00091     }Mode;
00092 
00093     /**
00094      * \brief Enum defining a resource data type.
00095     */
00096     typedef enum {
00097         STRING,
00098         INTEGER,
00099         FLOAT,
00100         BOOLEAN,
00101         OPAQUE,
00102         TIME,
00103         OBJLINK
00104     }DataType;
00105 
00106     /**
00107      * Enum defining an operation that can be
00108      * supported by a given resource.
00109     */
00110     typedef enum {
00111         NOT_ALLOWED                 = 0x00,
00112         GET_ALLOWED                 = 0x01,
00113         PUT_ALLOWED                 = 0x02,
00114         GET_PUT_ALLOWED             = 0x03,
00115         POST_ALLOWED                = 0x04,
00116         GET_POST_ALLOWED            = 0x05,
00117         PUT_POST_ALLOWED            = 0x06,
00118         GET_PUT_POST_ALLOWED        = 0x07,
00119         DELETE_ALLOWED              = 0x08,
00120         GET_DELETE_ALLOWED          = 0x09,
00121         PUT_DELETE_ALLOWED          = 0x0A,
00122         GET_PUT_DELETE_ALLOWED      = 0x0B,
00123         POST_DELETE_ALLOWED         = 0x0C,
00124         GET_POST_DELETE_ALLOWED     = 0x0D,
00125         PUT_POST_DELETE_ALLOWED     = 0x0E,
00126         GET_PUT_POST_DELETE_ALLOWED = 0x0F
00127     }Operation;
00128 
00129     enum MaxPathSize {
00130         MAX_NAME_SIZE = 64,
00131         MAX_INSTANCE_SIZE = 5,
00132 
00133         MAX_PATH_SIZE = ((MAX_NAME_SIZE * 2) + (MAX_INSTANCE_SIZE * 2) + 3 + 1),
00134         MAX_PATH_SIZE_2 = ((MAX_NAME_SIZE * 2) + MAX_INSTANCE_SIZE + 2 + 1),
00135         MAX_PATH_SIZE_3 = (MAX_NAME_SIZE + (MAX_INSTANCE_SIZE * 2) + 2 + 1),
00136         MAX_PATH_SIZE_4 = (MAX_NAME_SIZE + MAX_INSTANCE_SIZE + 1 + 1)
00137     };
00138 
00139     typedef void(*notification_delivery_status_cb) (const M2MBase& base,
00140                                                     const NotificationDeliveryStatus status,
00141                                                     void *client_args);
00142 
00143     typedef struct lwm2m_parameters {
00144         //add multiple_instances
00145         uint32_t            max_age; // todo: add flag
00146         union {
00147             char*               name; //for backwards compatibility
00148             uint16_t            instance_id; // XXX: this is not properly aligned now, need to reorder these after the elimination is done
00149         } identifier;
00150         sn_nsdl_dynamic_resource_parameters_s *dynamic_resource_params;
00151         BaseType            base_type : 3;
00152         M2MBase::DataType   data_type : 3;
00153         bool                multiple_instance;
00154         bool                free_on_delete;   /**< true if struct is dynamically allocated and it
00155                                                  and its members (name) are to be freed on destructor.
00156                                                  Note: the sn_nsdl_dynamic_resource_parameters_s has
00157                                                  its own similar, independent flag.
00158                                                  Note: this also serves as a read-only flag. */
00159        bool                 identifier_int_type;
00160        bool                 read_write_callback_set; /** If set all the read and write operations are handled in callbacks
00161                                                          and the resource value is not stored anymore in M2MResourceBase. */
00162     } lwm2m_parameters_s;
00163 
00164 protected:
00165 
00166     // Prevents the use of default constructor.
00167     M2MBase();
00168 
00169     // Prevents the use of assignment operator.
00170     M2MBase& operator=( const M2MBase& /*other*/ );
00171 
00172     // Prevents the use of copy constructor
00173     M2MBase( const M2MBase& /*other*/ );
00174 
00175     /**
00176      * \brief Constructor
00177      * \param name Name of the object created.
00178      * \param mode Type of the resource.
00179      * \param resource_type Textual information of resource.
00180      * \param path Path of the object like 3/0/1
00181      * \param external_blockwise_store If true CoAP blocks are passed to application through callbacks
00182      *        otherwise handled in mbed-client-c.
00183      */
00184     M2MBase(const String &name,
00185             M2MBase::Mode mode,
00186 #ifndef DISABLE_RESOURCE_TYPE
00187             const String &resource_type,
00188 #endif
00189             char *path,
00190             bool external_blockwise_store,
00191             bool multiple_instance,
00192             M2MBase::DataType type = M2MBase::OBJLINK);
00193 
00194     M2MBase(const lwm2m_parameters_s* s);
00195 
00196 public:
00197 
00198     /**
00199      * Destructor
00200      */
00201     virtual ~M2MBase();
00202 
00203     /**
00204      * \brief Sets the operation type for an object.
00205      * \param operation The operation to be set.
00206      */
00207     void set_operation(M2MBase::Operation operation);
00208 
00209 #if !defined(MEMORY_OPTIMIZED_API) || defined(RESOURCE_ATTRIBUTES_LIST)
00210     /**
00211      * \brief Sets the interface description of the object.
00212      * \param description The description to be set.
00213      */
00214 #if !defined(DISABLE_INTERFACE_DESCRIPTION) || defined(RESOURCE_ATTRIBUTES_LIST)
00215     void set_interface_description(const String &description);
00216 
00217     /**
00218      * \brief Sets the interface description of the object.
00219      * \param description The description to be set.
00220      */
00221     void set_interface_description(const char *description);
00222 
00223     /**
00224      * \brief Returns the interface description of the object.
00225      * \return The interface description of the object.
00226      */
00227     const char* interface_description() const;
00228 #endif
00229 #if !defined(DISABLE_RESOURCE_TYPE) || defined(RESOURCE_ATTRIBUTES_LIST)
00230     /**
00231      * \brief Sets the resource type of the object.
00232      * \param resource_type The resource type to be set.
00233      */
00234     virtual void set_resource_type(const String &resource_type);
00235 
00236     /**
00237      * \brief Sets the resource type of the object.
00238      * \param resource_type The resource type to be set.
00239      */
00240     virtual void set_resource_type(const char *resource_type);
00241 
00242     /**
00243      * \brief Returns the resource type of the object.
00244      * \return The resource type of the object.
00245      */
00246     const char* resource_type() const;
00247 #endif
00248 #endif
00249 
00250     /**
00251      * \brief Sets the CoAP content type of the object.
00252      * \param content_type The content type to be set based on
00253      * CoAP specifications.
00254      */
00255     void set_coap_content_type(const uint16_t content_type);
00256 
00257     /**
00258      * \brief Sets the observable mode for the object.
00259      * \param observable A value for the observation.
00260      */
00261     void set_observable(bool observable);
00262 
00263     /**
00264      * \brief Sets the object to be auto-observable.
00265      *
00266      * \note This is not a standard CoAP or LWM2M feature and it only works in mbed Cloud.
00267      * \note This must be called before registration process, since this info must be in a registration message.
00268      * \note Auto-observable will take higher precedence if both observable methods are set.
00269      *
00270      * \param auto_observable Is auto-obs feature enabled or not.
00271      */
00272     void set_auto_observable(bool auto_observable);
00273 
00274     /**
00275      * \brief Adds the observation level for the object.
00276      * \param observation_level The level of observation.
00277      */
00278     virtual void add_observation_level(M2MBase::Observation observation_level);
00279 
00280     /**
00281      * \brief Removes the observation level for the object.
00282      * \param observation_level The level of observation.
00283      */
00284     virtual void remove_observation_level(M2MBase::Observation observation_level);
00285 
00286     /**
00287      * \brief Sets the object under observation.
00288      * \param observed The value for observation. When true, starts observing. When false, the ongoing observation is cancelled.
00289      * \param handler A handler object for sending
00290      * observation callbacks.
00291      */
00292     void set_under_observation(bool observed,
00293                                M2MObservationHandler *handler);
00294     /**
00295      * \brief Returns the Observation Handler object.
00296      * \return M2MObservationHandler object.
00297     */
00298     virtual M2MObservationHandler* observation_handler() const = 0;
00299 
00300     /**
00301      * \brief Sets the observation handler
00302      * \param handler Observation handler
00303     */
00304     virtual void set_observation_handler(M2MObservationHandler *handler) = 0;
00305 
00306     /**
00307      * \brief Sets the instance ID of the object.
00308      * \param instance_id The instance ID of the object.
00309      */
00310     void set_instance_id(const uint16_t instance_id);
00311 
00312     /**
00313      * \brief Sets the max age for the resource value to be cached.
00314      * \param max_age The max age in seconds.
00315      */
00316     void set_max_age(const uint32_t max_age);
00317 
00318     /**
00319      * \brief Returns the object type.
00320      * \return The base type of the object.
00321      */
00322     M2MBase::BaseType base_type() const;
00323 
00324     /**
00325      * \brief Returns the operation type of the object.
00326      * \return The supported operation on the object.
00327      */
00328     M2MBase::Operation operation() const;
00329 
00330     /**
00331      * \brief Returns the object name.
00332      * \return The name of the object.
00333      */
00334     const char* name() const;
00335 
00336     /**
00337      * \brief Returns the object name in integer.
00338      * \return The name of the object in integer.
00339      */
00340     int32_t name_id() const;
00341 
00342     /**
00343      * \brief Returns the object's instance ID.
00344      * \returns The instance ID of the object.
00345      */
00346     uint16_t instance_id() const;
00347 
00348     /**
00349      * \brief Returns the path of the object.
00350      * \return The path of the object (eg. 3/0/1).
00351      */
00352     const char* uri_path() const;
00353 
00354     /**
00355      * \brief Returns the CoAP content type of the object.
00356      * \return The CoAP content type of the object.
00357      */
00358     uint16_t coap_content_type() const;
00359 
00360     /**
00361      * \brief Returns the observation status of the object.
00362      * \return True if observable, else false.
00363      */
00364     bool is_observable() const;
00365 
00366     /**
00367      * \brief Returns the observation level of the object.
00368      * \return The observation level of the object.
00369      */
00370     M2MBase::Observation observation_level() const;
00371 
00372     /**
00373      * \brief Returns the mode of the resource.
00374      * \return The mode of the resource.
00375      */
00376      Mode mode() const;
00377 
00378     /**
00379      * \brief Returns the observation number.
00380      * \return The observation number of the object.
00381      */
00382     uint16_t observation_number() const;
00383 
00384     /**
00385      * \brief Returns the max age for the resource value to be cached.
00386      * \return The maax age in seconds.
00387      */
00388     uint32_t max_age() const;
00389 
00390     /**
00391      * \brief Parses the received query for the notification
00392      * attribute.
00393      * \param query The query that needs to be parsed.
00394      * \return True if required attributes are present, else false.
00395      */
00396     virtual bool handle_observation_attribute(const char *query);
00397 
00398     /**
00399      * \brief Handles GET request for the registered objects.
00400      * \param nsdl An NSDL handler for the CoAP library.
00401      * \param received_coap_header The received CoAP message from the server.
00402      * \param observation_handler A handler object for sending
00403      * observation callbacks.
00404      * \return sn_coap_hdr_s The message that needs to be sent to server.
00405      */
00406     virtual sn_coap_hdr_s* handle_get_request(nsdl_s *nsdl,
00407                                               sn_coap_hdr_s *received_coap_header,
00408                                               M2MObservationHandler *observation_handler = NULL);
00409     /**
00410      * \brief Handles PUT request for the registered objects.
00411      * \param nsdl An NSDL handler for the CoAP library.
00412      * \param received_coap_header The received CoAP message from the server.
00413      * \param observation_handler A handler object for sending
00414      * observation callbacks.
00415      * \param execute_value_updated True executes the "value_updated" callback.
00416      * \return sn_coap_hdr_s The message that needs to be sent to server.
00417      */
00418     virtual sn_coap_hdr_s* handle_put_request(nsdl_s *nsdl,
00419                                               sn_coap_hdr_s *received_coap_header,
00420                                               M2MObservationHandler *observation_handler,
00421                                               bool &execute_value_updated);
00422 
00423     /**
00424      * \brief Handles GET request for the registered objects.
00425      * \param nsdl An NSDL handler for the CoAP library.
00426      * \param received_coap_header The received CoAP message from the server.
00427      * \param observation_handler A handler object for sending
00428      * observation callbacks.
00429      * \param execute_value_updated True executes the "value_updated" callback.
00430      * \return sn_coap_hdr_s  The message that needs to be sent to server.
00431      */
00432     virtual sn_coap_hdr_s* handle_post_request(nsdl_s *nsdl,
00433                                                sn_coap_hdr_s *received_coap_header,
00434                                                M2MObservationHandler *observation_handler,
00435                                                bool &execute_value_updated,
00436                                                sn_nsdl_addr_s *address = NULL);
00437 
00438     /**
00439      * \brief Executes the function that is set in "set_notification_delivery_status_cb".
00440      */
00441     void send_notification_delivery_status(const M2MBase& object, const NotificationDeliveryStatus status);
00442 
00443     /**
00444      * \brief Sets whether this resource is published to server or not.
00445      * \param register_uri True sets the resource as part of registration message.
00446      */
00447     void set_register_uri(bool register_uri);
00448 
00449     /**
00450      * \brief Returns whether this resource is published to server or not.
00451      * \return True if the resource is a part of the registration message, else false.
00452      */
00453     bool register_uri();
00454 
00455     /**
00456      * @brief Returns whether this resource is under observation or not.
00457      * @return True if the resource is under observation, else false,
00458      */
00459     bool is_under_observation() const;
00460 
00461     /**
00462      * @brief Sets the function that is executed when this
00463      * object receives a PUT or POST command.
00464      * @param callback The function pointer that is called.
00465      * @return True, if callback could be set, false otherwise.
00466      */
00467     bool set_value_updated_function(value_updated_callback callback);
00468 
00469     /**
00470      * @brief Sets the function that is executed when this
00471      * object receives a PUT or POST command.
00472      * @param callback The function pointer that is called.
00473      * @return True, if callback could be set, false otherwise.
00474      */
00475     bool set_value_updated_function(value_updated_callback2 callback);
00476 
00477     /**
00478      * @brief Returns whether a callback function is set or not.
00479      * @return True if the callback function is set, else false.
00480      */
00481     bool is_value_updated_function_set() const;
00482 
00483     /**
00484      * @brief Calls the function that is set in the "set_value_updated_function".
00485      * @param name The name of the object.
00486      */
00487     void execute_value_updated(const String& name);
00488 
00489     /**
00490      * @brief Returns length of the object name.
00491      * @return Length of the object name.
00492      */
00493     size_t resource_name_length() const;
00494 
00495     /**
00496      * @brief Returns the resource information.
00497      * @return Resource information.
00498      */
00499     sn_nsdl_dynamic_resource_parameters_s* get_nsdl_resource() const;
00500 
00501     /**
00502      * @brief Returns the resource structure.
00503      * @return Resource structure.
00504      */
00505     M2MBase::lwm2m_parameters_s* get_lwm2m_parameters() const;
00506 
00507     /**
00508      * @brief Returns the notification message id.
00509      * @return Message id.
00510      */
00511     uint16_t get_notification_msgid() const;
00512 
00513     /**
00514      * @brief Sets the notification message id.
00515      * This is used to map RESET and EMPTY ACK messages.
00516      * @param msgid The message id.
00517      */
00518     void set_notification_msgid(uint16_t msgid);
00519 
00520     /**
00521      * @brief Sets the function that is executed when notification message state changes.
00522      * @param callback The function pointer that is called.
00523      * @param client_args The argument which is passed to the callback function.
00524      */
00525     bool set_notification_delivery_status_cb(notification_delivery_status_cb callback, void *client_args);
00526 
00527 #ifdef MBED_CLOUD_CLIENT_EDGE_EXTENSION
00528     static char* create_path(const M2MEndpoint &parent, const char *name);
00529 #endif
00530     static char* create_path(const M2MObject &parent, const char *name);
00531     static char* create_path(const M2MObject &parent, uint16_t object_instance);
00532     static char* create_path(const M2MResource &parent, uint16_t resource_instance);
00533     static char* create_path(const M2MResource &parent, const char *name);
00534     static char* create_path(const M2MObjectInstance &parent, const char *name);
00535 
00536 protected : // from M2MReportObserver
00537 
00538     virtual bool observation_to_be_sent(const m2m::Vector<uint16_t> &changed_instance_ids,
00539                                         uint16_t obs_number,
00540                                         bool send_object = false);
00541 
00542 protected:
00543 
00544     /**
00545      * \brief Sets the base type for an object.
00546      * \param type The base type of the object.
00547      */
00548     void set_base_type(M2MBase::BaseType type);
00549 
00550     /**
00551      * \brief Memory allocation required for libCoap.
00552      * \param size The size of memory to be reserved.
00553     */
00554     static void* memory_alloc(uint32_t size);
00555 
00556     /**
00557      * \brief Memory free functions required for libCoap.
00558      * \param ptr The object whose memory needs to be freed.
00559     */
00560     static void memory_free(void *ptr);
00561 
00562     /**
00563      * \brief Allocate and make a copy of given zero terminated string. This
00564      * is functionally equivalent with strdup().
00565      * \param source The source string to copy, may not be NULL.
00566     */
00567     static char* alloc_string_copy(const char* source);
00568 
00569     /**
00570      * \brief Allocate (size + 1) amount of memory, copy size bytes into
00571      * it and add zero termination.
00572      * \param source The source string to copy, may not be NULL.
00573      * \param size The size of memory to be reserved.
00574     */
00575     static uint8_t* alloc_string_copy(const uint8_t* source, uint32_t size);
00576 
00577     /**
00578      * \brief Allocate (size) amount of memory, copy size bytes into it.
00579      * \param source The source buffer to copy, may not be NULL.
00580      * \param size The size of memory to be reserved.
00581     */
00582     static uint8_t* alloc_copy(const uint8_t* source, uint32_t size);
00583 
00584     // validate string length to be [min_length..max_length]
00585     static bool validate_string_length(const String &string, size_t min_length, size_t max_length);
00586     static bool validate_string_length(const char* string, size_t min_length, size_t max_length);
00587 
00588     /**
00589      * \brief Create Report Handler object.
00590      * \return M2MReportHandler object.
00591     */
00592     M2MReportHandler* create_report_handler();
00593 
00594     /**
00595      * \brief Returns the Report Handler object.
00596      * \return M2MReportHandler object.
00597     */
00598     M2MReportHandler* report_handler() const;
00599 
00600     static bool build_path(StringBuffer<MAX_PATH_SIZE> &buffer, const char *s1, uint16_t i1, const char *s2, uint16_t i2);
00601 
00602     static bool build_path(StringBuffer<MAX_PATH_SIZE_2> &buffer, const char *s1, uint16_t i1, const char *s2);
00603 
00604     static bool build_path(StringBuffer<MAX_PATH_SIZE_3> &buffer, const char *s1, uint16_t i1, uint16_t i2);
00605 
00606     static bool build_path(StringBuffer<MAX_PATH_SIZE_4> &buffer, const char *s1, uint16_t i1);
00607 
00608     static char* stringdup(const char* s);
00609 
00610     /**
00611      * \brief Delete the resource structures owned by this object. Note: this needs
00612      * to be called separately from each subclass' destructor as this method uses a
00613      * virtual method and the call needs to be done at same class which has the
00614      * implementation of the pure virtual method.
00615      */
00616     void free_resources();
00617 
00618     /**
00619      * \brief Returns notification send status.
00620      * \return Notification status.
00621      */
00622     NotificationDeliveryStatus get_notification_delivery_status() const;
00623 
00624     /**
00625      * \brief Clears the notification send status to initial state.
00626      */
00627     void clear_notification_delivery_status();
00628 
00629     /**
00630      * \brief Provides the observation token of the object.
00631      * \param value[OUT] A pointer to the value of the token.
00632      * \param value_length[OUT] The length of the token pointer.
00633      */
00634     void get_observation_token(uint8_t *token, uint8_t &token_length) const;
00635 
00636     /**
00637      * \brief Sets the observation token value.
00638      * \param token A pointer to the token of the resource.
00639      * \param length The length of the token pointer.
00640      */
00641     void set_observation_token(const uint8_t *token,
00642                                const uint8_t length);
00643 
00644     /*
00645      * \brief The data has changed and it needs to be updated into Mbed Cloud.
00646      *        Current implementation maintains the changed state only in M2MEndpoint. If any of the changes in an
00647      *        object changes the M2M registration structure, the information is propagated to M2MEndpoint using
00648      *        this interface.
00649      */
00650     virtual void set_changed();
00651 
00652     /*
00653      * \brief Returns the owner object. Can return NULL if the object has no parent.
00654      */
00655     virtual M2MBase *get_parent() const;
00656 
00657   private:
00658     static bool is_integer(const String &value);
00659 
00660     static bool is_integer(const char *value);
00661 
00662     static char* create_path_base(const M2MBase &parent, const char *name);
00663 
00664 private:
00665     lwm2m_parameters_s          *_sn_resource;
00666     M2MReportHandler            *_report_handler; // TODO: can be broken down to smaller classes with inheritance.
00667 
00668 friend class Test_M2MBase;
00669 friend class Test_M2MObject;
00670 friend class M2MNsdlInterface;
00671 friend class M2MInterfaceFactory;
00672 friend class M2MObject;
00673 };
00674 
00675 #endif // M2M_BASE_H
00676