12c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* 22c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Copyright (C) 2004-2010 NXP Software 32c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Copyright (C) 2010 The Android Open Source Project 42c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * 52c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Licensed under the Apache License, Version 2.0 (the "License"); 62c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * you may not use this file except in compliance with the License. 72c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * You may obtain a copy of the License at 82c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * 92c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * http://www.apache.org/licenses/LICENSE-2.0 102c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * 112c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * Unless required by applicable law or agreed to in writing, software 122c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * distributed under the License is distributed on an "AS IS" BASIS, 132c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 142c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * See the License for the specific language governing permissions and 152c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent * limitations under the License. 162c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent */ 172c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 182c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent#include "LVPSA_QPD.h" 192c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent#include "LVPSA_Private.h" 202c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 212c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/************************************************************************************/ 222c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 232c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* FUNCTION: LVPSA_QPD_WritePeak */ 242c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 252c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* DESCRIPTION: */ 262c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* Write a level value in the buffer in the corresponding band. */ 272c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 282c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* PARAMETERS: */ 292c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* pInst Pointer to the LVPSA instance */ 302c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* ppWrite Pointer to pointer to the buffer */ 312c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* CallNumber Number of the band the value should be written in */ 322c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* Value Value to write in the buffer */ 332c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 342c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* RETURNS: void */ 352c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 362c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/************************************************************************************/ 372c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurentvoid LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst, 382c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_UINT8 **ppWrite, 392c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 BandIndex, 402c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 Value ); 412c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 422c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 432c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 442c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/************************************************************************************/ 452c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 462c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* FUNCTION: LVPSA_QPD_Process */ 472c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 482c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* DESCRIPTION: */ 492c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* Apply downsampling, post gain, quasi peak filtering and write the levels values */ 502c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* in the buffer every 20 ms. */ 512c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 522c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* PARAMETERS: */ 532c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 542c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* RETURNS: void */ 552c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 562c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/************************************************************************************/ 572c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurentvoid LVPSA_QPD_Process ( void *hInstance, 582c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 *pInSamps, 592c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 numSamples, 602c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 BandIndex) 612c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent{ 622c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 632c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /****************************************************************************** 642c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent PARAMETERS 652c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *******************************************************************************/ 662c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVPSA_InstancePr_t *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance; 672c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent QPD_State_t *pQPDState = (QPD_State_t*)&pLVPSA_Inst->pQPD_States[BandIndex]; 682c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 692c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Pointer to taps */ 702c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32* pDelay = pQPDState->pDelay; 712c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 722c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Parameters needed during quasi peak calculations */ 732c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32 X0; 742c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32 temp,temp2; 752c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32 accu; 762c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 Xg0; 772c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 D0; 782c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 V0 = (LVM_INT16)(*pDelay); 792c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 802c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Filter's coef */ 812c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32 Kp = pQPDState->Coefs[0]; 822c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32 Km = pQPDState->Coefs[1]; 832c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 842c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 ii = numSamples; 852c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 862c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_UINT8 *pWrite = pLVPSA_Inst->pSpectralDataBufferWritePointer; 872c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT32 BufferUpdateSamplesCount = pLVPSA_Inst->BufferUpdateSamplesCount; 882c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_UINT16 DownSamplingFactor = pLVPSA_Inst->DownSamplingFactor; 892c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 902c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /****************************************************************************** 912c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent INITIALIZATION 922c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *******************************************************************************/ 932c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Correct the pointer to take the first down sampled signal sample */ 942c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pInSamps += pLVPSA_Inst->DownSamplingCount; 952c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Correct also the number of samples */ 962c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent ii = (LVM_INT16)(ii - (LVM_INT16)pLVPSA_Inst->DownSamplingCount); 972c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 982c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent while (ii > 0) 992c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 1002c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Apply post gain */ 1012c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent X0 = ((*pInSamps) * pLVPSA_Inst->pPostGains[BandIndex]) >> (LVPSA_GAINSHIFT-1); /* - 1 to compensate scaling in process function*/ 1022c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pInSamps = pInSamps + DownSamplingFactor; 1032c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1042c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Saturate and take absolute value */ 1052c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if(X0 < 0) 1062c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent X0 = -X0; 1072c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if (X0 > 0x7FFF) 1082c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent Xg0 = 0x7FFF; 1092c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent else 1102c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent Xg0 = (LVM_INT16)(X0); 1112c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1122c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1132c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Quasi peak filter calculation */ 1142c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent D0 = (LVM_INT16)(Xg0 - V0); 1152c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1162c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent temp2 = (LVM_INT32)D0; 1172c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent MUL32x32INTO32(temp2,Kp,accu,31); 1182c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1192c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent D0 = (LVM_INT16)(D0>>1); 1202c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if (D0 < 0){ 1212c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent D0 = (LVM_INT16)(-D0); 1222c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1232c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1242c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent temp2 = (LVM_INT32)D0; 1252c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent MUL32x32INTO32((LVM_INT32)D0,Km,temp,31); 1262c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent accu +=temp + Xg0; 1272c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1282c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if (accu > 0x7FFF) 1292c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent accu = 0x7FFF; 1302c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent else if(accu < 0) 1312c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent accu = 0x0000; 1322c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1332c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent V0 = (LVM_INT16)accu; 1342c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1352c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if(((pLVPSA_Inst->nSamplesBufferUpdate - BufferUpdateSamplesCount) < DownSamplingFactor)) 1362c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 1372c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVPSA_QPD_WritePeak( pLVPSA_Inst, 1382c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent &pWrite, 1392c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent BandIndex, 1402c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent V0); 1412c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent BufferUpdateSamplesCount -= pLVPSA_Inst->nSamplesBufferUpdate; 1422c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->LocalSamplesCount = (LVM_UINT16)(numSamples - ii); 1432c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1442c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent BufferUpdateSamplesCount+=DownSamplingFactor; 1452c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1462c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent ii = (LVM_INT16)(ii-DownSamplingFactor); 1472c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1482c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1492c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1502c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Store last taps in memory */ 1512c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *pDelay = (LVM_INT32)(V0); 1522c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1532c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* If this is the last call to the function after last band processing, 1542c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent update the parameters. */ 1552c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if(BandIndex == (pLVPSA_Inst->nRelevantFilters-1)) 1562c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 1572c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite; 1582c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Adjustment for 11025Hz input, 220,5 is normally 1592c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent the exact number of samples for 20ms.*/ 1602c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if((pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite)&&(pLVPSA_Inst->CurrentParams.Fs == LVM_FS_11025)) 1612c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 1622c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if(pLVPSA_Inst->nSamplesBufferUpdate == 220) 1632c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 1642c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->nSamplesBufferUpdate = 221; 1652c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1662c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent else 1672c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 1682c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->nSamplesBufferUpdate = 220; 1692c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1702c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1712c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->pSpectralDataBufferWritePointer = pWrite; 1722c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->BufferUpdateSamplesCount = BufferUpdateSamplesCount; 1732c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pLVPSA_Inst->DownSamplingCount = (LVM_UINT16)(-ii); 1742c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 1752c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent} 1762c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 1772c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/************************************************************************************/ 1782c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 1792c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* FUNCTION: LVPSA_QPD_WritePeak */ 1802c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 1812c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* DESCRIPTION: */ 1822c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* Write a level value in the spectrum data buffer in the corresponding band. */ 1832c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 1842c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* PARAMETERS: */ 1852c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* pLVPSA_Inst Pointer to the LVPSA instance */ 1862c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* ppWrite Pointer to pointer to the buffer */ 1872c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* CallNumber Number of the band the value should be written in */ 1882c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* Value Value to write in the spectrum data buffer */ 1892c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 1902c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* RETURNS: void */ 1912c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/* */ 1922c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent/************************************************************************************/ 1932c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurentvoid LVPSA_QPD_WritePeak( pLVPSA_InstancePr_t pLVPSA_Inst, 1942c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_UINT8 **ppWrite, 1952c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 BandIndex, 1962c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_INT16 Value ) 1972c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent{ 1982c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent LVM_UINT8 *pWrite = *ppWrite; 1992c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 2002c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 2012c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent /* Write the value and update the write pointer */ 2022c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *(pWrite + BandIndex) = (LVM_UINT8)(Value>>7); 2032c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pWrite += pLVPSA_Inst->nBands; 2042c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent if (pWrite == (pLVPSA_Inst->pSpectralDataBufferStart + pLVPSA_Inst->nBands * pLVPSA_Inst->SpectralDataBufferLength)) 2052c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent { 2062c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent pWrite = pLVPSA_Inst->pSpectralDataBufferStart; 2072c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent } 2082c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 2092c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent *ppWrite = pWrite; 2102c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 2112c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent} 2122c8e5cab3faa6d360e222b7a6c40a80083d021acEric Laurent 213