Camera3: Enable preview

- initial_reg_flag is used to indicate whether to queue
  buffers to the hardware before streamon. Remove code
  in mm_stream_qbuf where VIDIOC_REQBUFS is skipped if
  any of initial_reg_flag is 0.
- Apply change I5f8f5e2b2c86dfae3cae2b76886dd96eb1d261cc:
  "QCamera2: Trigger buffer cache invalidate just before queuing"
- Use PRIV_FLAGS_HW_TEXTURE private gralloc usage flag for
  preview frame.
- Improve member variables initialization and cleanup
  for QCamera3HWI class.
- Remove redundant functions in QCamera3HWI.
- Add cleanInvalidateBuf function pointer to mMemVtbl.

Change-Id: I416bd169eb0d98ed268c41f128636ed451c6de23
diff --git a/camera/QCamera2/HAL3/QCamera3Channel.cpp b/camera/QCamera2/HAL3/QCamera3Channel.cpp
index 79b8fe1..358ea69 100644
--- a/camera/QCamera2/HAL3/QCamera3Channel.cpp
+++ b/camera/QCamera2/HAL3/QCamera3Channel.cpp
@@ -493,7 +493,7 @@
         if (priv_handle->flags & private_handle_t::PRIV_FLAGS_VIDEO_ENCODER) {
             streamType = CAM_STREAM_TYPE_VIDEO;
             streamFormat = CAM_FORMAT_YUV_420_NV12;
-        } else if (priv_handle->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY) {
+        } else if (priv_handle->flags & private_handle_t::PRIV_FLAGS_HW_TEXTURE) {
             streamType = CAM_STREAM_TYPE_PREVIEW;
             streamFormat = CAM_FORMAT_YUV_420_NV21;
         } else {
@@ -644,7 +644,7 @@
         return rc;
     }
 
-    streamDim.width = sizeof(parm_buffer_t),
+    streamDim.width = sizeof(metadata_buffer_t),
     streamDim.height = 1;
     rc = QCamera3Channel::addStream(CAM_STREAM_TYPE_METADATA, CAM_FORMAT_MAX,
         streamDim, MIN_STREAMING_BUFFER_NUM);
@@ -695,9 +695,9 @@
 QCamera3Memory* QCamera3MetadataChannel::getStreamBufs(uint32_t len)
 {
     int rc;
-    if (len != sizeof(parm_buffer_t)) {
+    if (len != sizeof(metadata_buffer_t)) {
         ALOGE("%s: size doesn't match %d vs %d", __func__,
-                len, sizeof(parm_buffer_t));
+                len, sizeof(metadata_buffer_t));
         return NULL;
     }
     mMemory = new QCamera3HeapMemory();
@@ -712,7 +712,7 @@
         mMemory = NULL;
         return NULL;
     }
-    memset(mMemory->getPtr(0), 0, sizeof(parm_buffer_t));
+    memset(mMemory->getPtr(0), 0, sizeof(metadata_buffer_t));
     return mMemory;
 }
 
diff --git a/camera/QCamera2/HAL3/QCamera3HWI.cpp b/camera/QCamera2/HAL3/QCamera3HWI.cpp
index 142b483..6bbd748 100644
--- a/camera/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/camera/QCamera2/HAL3/QCamera3HWI.cpp
@@ -147,6 +147,11 @@
       mCameraHandle(NULL),
       mCameraOpened(false),
       mCallbackOps(NULL),
+      mInputStream(NULL),
+      mMetadataChannel(NULL),
+      mFirstRequest(false),
+      mParamHeap(NULL),
+      mParameters(NULL),
       mJpegSettings(NULL)
 {
     mCameraDevice.common.tag = HARDWARE_DEVICE_TAG;
@@ -161,6 +166,10 @@
     mPendingRequest = 0;
 
     pthread_mutex_init(&mMutex, NULL);
+    pthread_mutex_init(&mCaptureResultLock, NULL);
+
+    for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++)
+        mDefaultMetadata[i] = NULL;
 }
 
 /*===========================================================================
@@ -178,12 +187,18 @@
         free(mJpegSettings);
         mJpegSettings = NULL;
     }
+    deinitParameters();
     closeCamera();
 
+    for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++)
+        if (mDefaultMetadata[i])
+            free_camera_metadata(mDefaultMetadata[i]);
+
     pthread_mutex_destroy(&mRequestLock);
     pthread_cond_destroy(&mRequestCond);
 
     pthread_mutex_destroy(&mMutex);
+    pthread_mutex_destroy(&mCaptureResultLock);
 }
 
 /*===========================================================================
@@ -266,41 +281,6 @@
 }
 
 /*===========================================================================
- * FUNCTION   : sendCaptureResult
- *
- * DESCRIPTION: send completed capture result metadata buffer along with possibly
- *              completed output stream buffers to the framework
- *
- * PARAMETERS :
- *
- * RETURN     :
- *==========================================================================*/
-void QCamera3HardwareInterface::sendCaptureResult(const struct camera3_callback_ops *,
-                                                 const camera3_capture_result_t *result)
-{
-    //TODO - Implement
-}
-
-/*===========================================================================
- * FUNCTION   : notify
- *
- * DESCRIPTION: Asynchronous notification callback to framework
- *
- * PARAMETERS :
- *
- * RETURN     :
- *
- *
- *==========================================================================*/
-
-void QCamera3HardwareInterface::notify(const struct camera3_callback_ops *,
-                                       const camera3_notify_msg_t *msg)
-{
-    //TODO - Implement
-}
-
-
-/*===========================================================================
  * FUNCTION   : initialize
  *
  * DESCRIPTION: Initialize frameworks callback functions
@@ -318,6 +298,11 @@
 
     pthread_mutex_lock(&mMutex);
 
+    rc = initParameters();
+    if (rc < 0) {
+        ALOGE("%s: initParamters failed %d", __func__, rc);
+       goto err1;
+    }
     //Create metadata channel and initialize it
     mMetadataChannel = new QCamera3MetadataChannel(mCameraHandle->camera_handle,
                     mCameraHandle->ops, captureResultCb,
@@ -325,47 +310,24 @@
     if (mMetadataChannel == NULL) {
         ALOGE("%s: failed to allocate metadata channel", __func__);
         rc = -ENOMEM;
-        goto err1;
+        goto err2;
     }
     rc = mMetadataChannel->initialize();
     if (rc < 0) {
         ALOGE("%s: metadata channel initialization failed", __func__);
-        goto err2;
-    }
-
-    /* Initialize parameter heap and structure */
-    mParamHeap = new QCamera3HeapMemory();
-    if (mParamHeap == NULL) {
-        ALOGE("%s: creation of mParamHeap failed", __func__);
-        goto err2;
-    }
-    rc = mParamHeap->allocate(1, sizeof(parm_buffer_t), false);
-    if (rc < 0) {
-        ALOGE("%s: allocation of mParamHeap failed", __func__);
         goto err3;
     }
-    rc = mCameraHandle->ops->map_buf(mCameraHandle->camera_handle,
-                CAM_MAPPING_BUF_TYPE_PARM_BUF,
-                mParamHeap->getFd(0), sizeof(parm_buffer_t));
-    if (rc < 0) {
-        ALOGE("%s: map_buf failed for mParamHeap", __func__);
-        goto err4;
-    }
-    mParameters = (parm_buffer_t *)DATA_PTR(mParamHeap, 0);
 
     mCallbackOps = callback_ops;
 
     pthread_mutex_unlock(&mMutex);
     return 0;
 
-err4:
-    mParamHeap->deallocate();
 err3:
-    delete mParamHeap;
-    mParamHeap = NULL;
-err2:
     delete mMetadataChannel;
     mMetadataChannel = NULL;
+err2:
+    deinitParameters();
 err1:
     pthread_mutex_unlock(&mMutex);
     return rc;
@@ -387,7 +349,7 @@
         camera3_stream_configuration_t *streamList)
 {
     pthread_mutex_lock(&mMutex);
-    int rc;
+    int rc = 0;
 
     // Sanity check stream_list
     if (streamList == NULL) {
@@ -426,7 +388,7 @@
     /* TODO: Clean up no longer used streams, and maintain others if this
      * is not the 1st time configureStreams is called */
 
-    mMetadataChannel->stop();
+    //mMetadataChannel->stop();
 
     /* Allocate channel objects for the requested streams */
     for (size_t i = 0; i < streamList->num_streams; i++) {
@@ -502,11 +464,13 @@
         }
     }
 
-    // Cannot reuse settings across configure call
+    //settings/parameters don't carry over for new configureStreams
     memset(mParameters, 0, sizeof(parm_buffer_t));
+    mFirstRequest = true;
+
 end:
     pthread_mutex_unlock(&mMutex);
-    return 0;
+    return rc;
 }
 
 /*===========================================================================
@@ -673,12 +637,12 @@
     uint32_t frameNumber = request->frame_number;
 
     rc = setFrameParameters(request->frame_number, request->settings);
-
     if (rc < 0) {
         ALOGE("%s: fail to set frame parameters", __func__);
         pthread_mutex_unlock(&mMutex);
         return rc;
     }
+    mFirstRequest = false;
 
     // Acquire all request buffers first
     for (size_t i = 0; i < request->num_output_buffers; i++) {
@@ -785,11 +749,13 @@
 /*===========================================================================
  * FUNCTION   : captureResultCb
  *
- * DESCRIPTION: Callback handler for all capture result (streams, as well as metadata)
+ * DESCRIPTION: Callback handler for all capture result
+ *              (streams, as well as metadata)
  *
  * PARAMETERS :
  *   @metadata : metadata information
- *   @buffer   : actual gralloc buffer to be returned to frameworks. NULL if metadata.
+ *   @buffer   : actual gralloc buffer to be returned to frameworks.
+ *               NULL if metadata.
  *
  * RETURN     : NONE
  *==========================================================================*/
@@ -799,7 +765,6 @@
     pthread_mutex_lock(&mCaptureResultLock);
     camera3_capture_result_t result;
 
-
     if (metadata) {
         // Signal to unblock processCaptureRequest
         pthread_mutex_lock(&mRequestLock);
@@ -807,25 +772,56 @@
         pthread_cond_signal(&mRequestCond);
         pthread_mutex_unlock(&mRequestLock);
 
-        uint32_t *frame_number = (uint32_t *)POINTER_OF(CAM_INTF_META_FRAME_NUMBER, metadata);
+        int32_t frame_number_valid = *(int32_t *)
+            POINTER_OF(CAM_INTF_META_FRAME_NUMBER_VALID, metadata);
+        ALOGE("%s: frame_number_valid = %d", __func__, frame_number_valid);
+        if (!frame_number_valid) {
+            ALOGI("%s: Not a valid frame number, used as SOF only", __func__);
+            goto done;
+        }
 
+        uint32_t frame_number = *(uint32_t *)
+            POINTER_OF(CAM_INTF_META_FRAME_NUMBER, metadata);
+#if 1
+        nsecs_t capture_time = 1000000 * frame_number * 33;
+#else
+        nsecs_t capture_time = *(int64_t *)
+            POINTER_OF(CAM_INTF_META_SENSOR_EXPOSURE_TIME, metadata);
+#endif
+        ALOGE("%s: notify frame_number = %d, capture_time = %lld", __func__,
+                frame_number, capture_time);
+
+        /* Send shutter notify */
+        camera3_notify_msg_t notify_msg;
+        notify_msg.type = CAMERA3_MSG_SHUTTER;
+        notify_msg.message.shutter.frame_number = frame_number;
+        notify_msg.message.shutter.timestamp = capture_time;
+        mCallbackOps->notify(mCallbackOps, &notify_msg);
+
+        /* send capture result with metadata only */
         result.result = translateCbMetadataToResultMetadata(metadata);
-        if (!result.result) {
-            result.frame_number = *frame_number;
+        if (result.result) {
+            result.frame_number = frame_number;
             result.num_output_buffers = 0;
             result.output_buffers = NULL;
             mCallbackOps->process_capture_result(mCallbackOps, &result);
 
+            ALOGE("%s: metadata frame_number = %d, capture_time = %ld",
+                    __func__, frame_number, capture_time);
             free_camera_metadata((camera_metadata_t*)result.result);
+        } else {
+            ALOGE("%s: metadata is NULL", __func__);
         }
     } else {
         result.result = NULL;
         result.frame_number = frame_number;
         result.num_output_buffers = 1;
         result.output_buffers = buffer;
+        ALOGE("%s: result frame_number = %d", __func__, frame_number);
         mCallbackOps->process_capture_result(mCallbackOps, &result);
     }
 
+done:
     pthread_mutex_unlock(&mCaptureResultLock);
     return;
 }
@@ -848,10 +844,16 @@
     CameraMetadata camMetadata;
     camera_metadata_t* resultMetadata;
 
-    uint32_t *frame_number =
-        (uint32_t *)POINTER_OF(CAM_INTF_META_FRAME_NUMBER, metadata);
-    nsecs_t captureTime = 1000000 * (*frame_number) * 33;
+#if 1
+    uint32_t frame_number = *(uint32_t *)
+        POINTER_OF(CAM_INTF_META_FRAME_NUMBER, metadata);
+    nsecs_t captureTime = 1000000 * frame_number * 33;
     camMetadata.update(ANDROID_SENSOR_TIMESTAMP, &captureTime, 1);
+#else
+    nsecs_t *captureTime = (nsecs_t *)POINTER_OF(CAM_INTF_META_SENSOR_TIMESTAMP, metadata);
+    camMetadata.update(ANDROID_SENSOR_TIMESTAMP, captureTime, 1);
+#endif
+
 
     /*CAM_INTF_META_HISTOGRAM - TODO*/
     /*cam_hist_stats_t  *histogram =
@@ -1047,7 +1049,7 @@
             CAM_MAX_MAP_WIDTH*CAM_MAX_MAP_HEIGHT);
 
     resultMetadata = camMetadata.release();
-    return NULL;
+    return resultMetadata;
 }
 
 /*===========================================================================
@@ -1211,12 +1213,31 @@
     }
 
     mParameters = (parm_buffer_t*) DATA_PTR(mParamHeap,0);
-    memset(mParameters, 0, sizeof(parm_buffer_t));
-    mParameters->first_flagged_entry = CAM_INTF_PARM_MAX;
     return rc;
 }
 
 /*===========================================================================
+ * FUNCTION   : deinitParameters
+ *
+ * DESCRIPTION: de-initialize camera parameters
+ *
+ * PARAMETERS :
+ *
+ * RETURN     : NONE
+ *==========================================================================*/
+void QCamera3HardwareInterface::deinitParameters()
+{
+    mCameraHandle->ops->unmap_buf(mCameraHandle->camera_handle,
+            CAM_MAPPING_BUF_TYPE_PARM_BUF);
+
+    mParamHeap->deallocate();
+    delete mParamHeap;
+    mParamHeap = NULL;
+
+    mParameters = NULL;
+}
+
+/*===========================================================================
  * FUNCTION   : initStaticMetadata
  *
  * DESCRIPTION: initialize the static metadata
@@ -2018,10 +2039,13 @@
 {
     /*translate from camera_metadata_t type to parm_type_t*/
     int rc = 0;
-    if (settings == NULL && mParameters == NULL) {
+    if (settings == NULL && mFirstRequest) {
         /*settings cannot be null for the first request*/
         return BAD_VALUE;
     }
+
+    mParameters->first_flagged_entry = CAM_INTF_PARM_MAX;
+
     /*we need to update the frame number in the parameters*/
     rc = AddSetParmEntryToBatch(mParameters, CAM_INTF_META_FRAME_NUMBER,
                                 sizeof(frame_id), &frame_id);
@@ -2030,9 +2054,10 @@
         return BAD_VALUE;
     }
     if(settings != NULL){
-        rc = translateMetadataToParameters(settings);
+        //rc = translateMetadataToParameters(settings);
     }
     /*set the parameters to backend*/
+    ALOGE("%s: %d", __func__, __LINE__);
     mCameraHandle->ops->set_parms(mCameraHandle->camera_handle, mParameters);
     return rc;
 }
diff --git a/camera/QCamera2/HAL3/QCamera3HWI.h b/camera/QCamera2/HAL3/QCamera3HWI.h
index 8e33554..c0b3c68 100644
--- a/camera/QCamera2/HAL3/QCamera3HWI.h
+++ b/camera/QCamera2/HAL3/QCamera3HWI.h
@@ -96,11 +96,6 @@
                 camera3_stream_buffer_t *buffer, uint32_t frame_number,
                 void *userdata);
 
-    void sendCaptureResult(const struct camera3_callback_ops *,
-                        const camera3_capture_result_t *result);
-    void notify(const struct camera3_callback_ops *,
-                        const camera3_notify_msg_t *msg);
-
     int initialize(const camera3_callback_ops_t *callback_ops);
     int configureStreams(camera3_stream_configuration_t *stream_list);
     int registerStreamBuffers(const camera3_stream_buffer_set_t *buffer_set);
@@ -113,6 +108,7 @@
     camera_metadata_t* translateCbMetadataToResultMetadata(metadata_buffer_t *metadata);
     int getJpegSettings(const camera_metadata_t *settings);
     int initParameters();
+    void deinitParameters();
 
     void captureResultCb(metadata_buffer_t *metadata,
                 camera3_stream_buffer_t *buffer, uint32_t frame_number);
@@ -157,6 +153,8 @@
     camera3_stream_t *mInputStream;
     QCamera3MetadataChannel *mMetadataChannel;
 
+     //First request yet to be processed after configureStreams
+    bool mFirstRequest;
     QCamera3HeapMemory *mParamHeap;
     parm_buffer_t* mParameters;
 
diff --git a/camera/QCamera2/HAL3/QCamera3Mem.cpp b/camera/QCamera2/HAL3/QCamera3Mem.cpp
index 75019d1..a50893d 100644
--- a/camera/QCamera2/HAL3/QCamera3Mem.cpp
+++ b/camera/QCamera2/HAL3/QCamera3Mem.cpp
@@ -97,6 +97,7 @@
 int QCamera3Memory::cacheOpsInternal(int index, unsigned int cmd, void *vaddr)
 {
     struct ion_flush_data cache_inv_data;
+    struct ion_custom_data custom_data;
     int ret = OK;
 
     if (index >= mBufferCount) {
@@ -105,16 +106,19 @@
     }
 
     memset(&cache_inv_data, 0, sizeof(cache_inv_data));
+    memset(&custom_data, 0, sizeof(custom_data));
     cache_inv_data.vaddr = vaddr;
     cache_inv_data.fd = mMemInfo[index].fd;
     cache_inv_data.handle = mMemInfo[index].handle;
     cache_inv_data.length = mMemInfo[index].size;
+    custom_data.cmd = cmd;
+    custom_data.arg = (unsigned long)&cache_inv_data;
 
-    ALOGD("%s: addr = %p, fd = %d, handle = %p length = %d, ION Fd = %d",
+    ALOGV("%s: addr = %p, fd = %d, handle = %p length = %d, ION Fd = %d",
          __func__, cache_inv_data.vaddr, cache_inv_data.fd,
          cache_inv_data.handle, cache_inv_data.length,
          mMemInfo[index].main_ion_fd);
-    ret = ioctl(mMemInfo[index].main_ion_fd, cmd, &cache_inv_data);
+    ret = ioctl(mMemInfo[index].main_ion_fd, ION_IOC_CUSTOM, &custom_data);
     if (ret < 0)
         ALOGE("%s: Cache Invalidate failed: %s\n", __func__, strerror(errno));
 
diff --git a/camera/QCamera2/HAL3/QCamera3Stream.cpp b/camera/QCamera2/HAL3/QCamera3Stream.cpp
index d750278..862e0e6 100644
--- a/camera/QCamera2/HAL3/QCamera3Stream.cpp
+++ b/camera/QCamera2/HAL3/QCamera3Stream.cpp
@@ -99,6 +99,52 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : invalidate_buf
+ *
+ * DESCRIPTION: static function entry to invalidate a specific stream buffer
+ *
+ * PARAMETERS :
+ *   @index      : index of the stream buffer to invalidate
+ *   @user_data  : user data ptr of ops_tbl
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3Stream::invalidate_buf(int index, void *user_data)
+{
+    QCamera3Stream *stream = reinterpret_cast<QCamera3Stream *>(user_data);
+    if (!stream) {
+        ALOGE("invalid stream pointer");
+        return NO_MEMORY;
+    }
+    return stream->invalidateBuf(index);
+}
+
+/*===========================================================================
+ * FUNCTION   : clean_invalidate_buf
+ *
+ * DESCRIPTION: static function entry to clean and invalidate a specific stream buffer
+ *
+ * PARAMETERS :
+ *   @index      : index of the stream buffer to invalidate
+ *   @user_data  : user data ptr of ops_tbl
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3Stream::clean_invalidate_buf(int index, void *user_data)
+{
+    QCamera3Stream *stream = reinterpret_cast<QCamera3Stream *>(user_data);
+    if (!stream) {
+        ALOGE("invalid stream pointer");
+        return NO_MEMORY;
+    }
+    return stream->cleanInvalidateBuf(index);
+}
+
+/*===========================================================================
  * FUNCTION   : QCamera3Stream
  *
  * DESCRIPTION: constructor of QCamera3Stream
@@ -132,6 +178,8 @@
     mMemVtbl.user_data = this;
     mMemVtbl.get_bufs = get_bufs;
     mMemVtbl.put_bufs = put_bufs;
+    mMemVtbl.invalidate_buf = invalidate_buf;
+    mMemVtbl.clean_invalidate_buf = clean_invalidate_buf;
     memset(&mFrameLenOffset, 0, sizeof(mFrameLenOffset));
     memcpy(&mPaddingInfo, paddingInfo, sizeof(cam_padding_info_t));
 }
@@ -438,9 +486,6 @@
     if (rc < 0)
         return FAILED_TRANSACTION;
 
-    if ( !isTypeOf(CAM_STREAM_TYPE_METADATA) ) {
-        mStreamBufs->invalidateCache(index);
-    }
     return rc;
 }
 
@@ -568,6 +613,40 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : invalidateBuf
+ *
+ * DESCRIPTION: invalidate a specific stream buffer
+ *
+ * PARAMETERS :
+ *   @index   : index of the buffer to invalidate
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3Stream::invalidateBuf(int index)
+{
+    return mStreamBufs->invalidateCache(index);
+}
+
+/*===========================================================================
+ * FUNCTION   : cleanInvalidateBuf
+ *
+ * DESCRIPTION: clean and invalidate a specific stream buffer
+ *
+ * PARAMETERS :
+ *   @index   : index of the buffer to invalidate
+ *
+ * RETURN     : int32_t type of status
+ *              NO_ERROR  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int32_t QCamera3Stream::cleanInvalidateBuf(int index)
+{
+    return mStreamBufs->cleanInvalidateCache(index);
+}
+
+/*===========================================================================
  * FUNCTION   : isTypeOf
  *
  * DESCRIPTION: helper function to determine if the stream is of the queried type
diff --git a/camera/QCamera2/HAL3/QCamera3Stream.h b/camera/QCamera2/HAL3/QCamera3Stream.h
index f3cf565..e98883c 100644
--- a/camera/QCamera2/HAL3/QCamera3Stream.h
+++ b/camera/QCamera2/HAL3/QCamera3Stream.h
@@ -113,6 +113,8 @@
     static int32_t put_bufs(
                      mm_camera_map_unmap_ops_tbl_t *ops_tbl,
                      void *user_data);
+    static int32_t invalidate_buf(int index, void *user_data);
+    static int32_t clean_invalidate_buf(int index, void *user_data);
 
     int32_t getBufs(cam_frame_len_offset_t *offset,
                      uint8_t *num_bufs,
@@ -120,6 +122,8 @@
                      mm_camera_buf_def_t **bufs,
                      mm_camera_map_unmap_ops_tbl_t *ops_tbl);
     int32_t putBufs(mm_camera_map_unmap_ops_tbl_t *ops_tbl);
+    int32_t invalidateBuf(int index);
+    int32_t cleanInvalidateBuf(int index);
 
 };