00001
00004 #ifndef FBXFILESDK_COMPONENTS_KBASELIB_KLIB_KARRAYUL_H
00005 #define FBXFILESDK_COMPONENTS_KBASELIB_KLIB_KARRAYUL_H
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include <fbxfilesdk/components/kbaselib/kbaselib_h.h>
00042
00043 #ifndef KFBX_PLUGIN
00044 #include <fbxfilesdk/components/kbaselib/klib/kdebug.h>
00045 #endif
00046
00047 #include <string.h>
00048 #include <stdlib.h>
00049
00050 #define KFBX_ARRAYUL_BLOCKSIZE 4
00051
00052 #include <fbxfilesdk/components/kbaselib/kbaselib_forward.h>
00053 #include <fbxfilesdk/fbxfilesdk_nsbegin.h>
00054
00055
00056
00057
00058 template< class Type > class KBaseStaticArray
00059 {
00060 protected:
00061 int mCount;
00062 Type *mArrayBuf;
00063
00064 public:
00065 inline int GetCount() { return mCount; }
00066
00068 inline Type &operator[](int pIndex)
00069 {
00070 #ifndef KFBX_PLUGIN
00071 K_ASSERT_MSG( pIndex >= 0 , "Buffer underflow");
00072 K_ASSERT_MSG( pIndex < mCount,"Buffer overflow.");
00073 #endif
00074 return mArrayBuf[pIndex];
00075 }
00076 };
00077
00078
00079 template< class Type, int Count > class KStaticArray : public KBaseStaticArray<Type>
00080 {
00081 public:
00082 Type mArray[Count];
00083 inline KStaticArray(){ this->mArrayBuf = mArray; this->mCount = Count;}
00084 };
00085
00086 template< class Type, int Count1, int Count2 > class KStaticArray2d
00087 {
00088 public:
00089 #if defined(KARCH_DEV_MSC) && (_MSC_VER <= 1200)// VC6
00090 KStaticArray<Type,Count2> *mArray;
00091
00092 KStaticArray2d() { mArray = new KStaticArray<Type,Count2>(Count1); }
00093 ~KStaticArray2d() { delete[] mArray; }
00094 #else
00095 KStaticArray<Type,Count2> mArray[Count1];
00096 #endif
00097
00098
00099 inline KStaticArray< Type, Count2 > &operator[](int pIndex)
00100 {
00101 #ifndef KFBX_PLUGIN
00102 K_ASSERT_MSG( pIndex >= 0 , "Buffer underflow.");
00103 K_ASSERT_MSG( pIndex < Count1,"Buffer overflow.");
00104 #endif
00105 return mArray[pIndex];
00106 }
00107 };
00108
00109
00110
00111
00112 class KBaseArraySize {
00113 public:
00114 KBaseArraySize( int pItemSize)
00115 : mItemSize(pItemSize)
00116 {
00117 }
00118 inline int GetTypeSize() const { return mItemSize; }
00119 private:
00120 int mItemSize;
00121 };
00122
00123 template <class T> class KBaseArraySizeType
00124 {
00125 public:
00126 inline int GetTypeSize() const { return sizeof(T); }
00127 };
00128
00129
00130 KFBX_DLL void KBaseArrayFree(char*);
00131 KFBX_DLL char* KBaseArrayRealloc(char*, size_t);
00132
00134
00135
00136
00137
00138
00139
00141 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00142 KFBX_DLL void* KBaseArrayGetAlloc();
00143 #endif
00144
00145 template <class TypeSize> class KBaseArray
00146 {
00147 protected:
00148 struct KHeader {
00149 int mArrayCount;
00150 int mBlockCount;
00151 };
00152
00153
00154 protected:
00159 inline KBaseArray(TypeSize pTypeSize)
00160 : mTypeSize(pTypeSize)
00161 {
00162 mBaseArray = NULL;
00163 #ifndef KFBX_PLUGIN
00164 K_ASSERT( pItemPerBlock > 0 );
00165 #endif
00166 }
00167
00168
00170 inline ~KBaseArray(){
00171 Clear ();
00172 }
00173
00181 inline int InsertAt(int pIndex, void *pItem)
00182 {
00183 int lArrayCount = GetArrayCount();
00184 int lBlockCount = GetBlockCount();
00185
00186 #ifndef KFBX_PLUGIN
00187 K_ASSERT( pIndex >= 0 );
00188 #endif
00189
00190 if (pIndex>lArrayCount) {
00191 pIndex = GetArrayCount();
00192 }
00193
00194 if (lArrayCount>= lBlockCount*KFBX_ARRAYUL_BLOCKSIZE)
00195 {
00196
00197
00198
00199 lBlockCount = ( 0 == lBlockCount ) ? 1 : lBlockCount * 2;
00200 mBaseArray = KBaseArrayRealloc(mBaseArray, (size_t) (lBlockCount*KFBX_ARRAYUL_BLOCKSIZE*GetTypeSize()) + GetHeaderOffset() );
00201 if(mBaseArray == NULL)
00202 {
00203 return -1;
00204 }
00205 }
00206
00207 if (pIndex<lArrayCount)
00208 {
00209
00210 memmove (&(mBaseArray[(pIndex+1)*GetTypeSize()+ GetHeaderOffset() ]), &(mBaseArray[(pIndex)*GetTypeSize()+ GetHeaderOffset()] ), GetTypeSize()*(lArrayCount-pIndex));
00211 }
00212
00213 memmove (&(mBaseArray[(pIndex)*GetTypeSize()+ GetHeaderOffset() ]), pItem, GetTypeSize());
00214
00215 SetArrayCount(lArrayCount+1);
00216 SetBlockCount(lBlockCount);
00217
00218 return pIndex;
00219 }
00220
00221
00228 inline void* GetAt(int pIndex) { return &(mBaseArray[(pIndex)*GetTypeSize()+ GetHeaderOffset() ]); }
00229
00236 inline void RemoveAt(int pIndex)
00237 {
00238
00239 #if defined(_DEBUG) && !defined(KARCH_ENV_MACOSX)
00240 if (!ValidateIndex( pIndex ))
00241 {
00242 return;
00243 }
00244 #endif
00245 int lArrayCount = GetArrayCount();
00246 if (pIndex+1<lArrayCount)
00247 {
00248 memmove (&(mBaseArray[(pIndex)*GetTypeSize()+ GetHeaderOffset() ]), &(mBaseArray[(pIndex+1)*GetTypeSize()+ GetHeaderOffset() ]), GetTypeSize()*(lArrayCount-pIndex-1));
00249 }
00250
00251 SetArrayCount( lArrayCount-1 );
00252
00253 #ifdef _DEBUG
00254 memset( &(mBaseArray[(GetArrayCount())*GetTypeSize()+ GetHeaderOffset() ]),0,GetTypeSize());
00255 #endif
00256 }
00257
00258
00264 inline bool ValidateIndex( int pIndex ) const
00265 {
00266 int lArrayCount = GetArrayCount();
00267 if (pIndex>=0 && pIndex<lArrayCount)
00268 {
00269 return true;
00270 } else
00271 {
00272 #ifndef KFBX_PLUGIN
00273 K_ASSERT_MSG_NOW(_T("ArrayTemplate : Index out of range"));
00274 #endif
00275 return false;
00276 }
00277 }
00278
00279
00280 public:
00284 inline int GetCount() const { return GetArrayCount(); }
00285
00287 inline void Clear()
00288 {
00289 if (mBaseArray!=NULL)
00290 {
00291 KBaseArrayFree(mBaseArray);
00292 mBaseArray = NULL;
00293 }
00294 }
00295
00296
00298 inline void Empty()
00299 {
00300 #ifndef KFBX_PLUGIN
00301 #ifdef _DEBUG
00302 memset( mBaseArray+ GetHeaderOffset() ,0,GetArrayCount()*GetTypeSize());
00303 #endif
00304 #endif
00305 SetArrayCount(0);
00306 }
00307
00308
00314 inline int Reserve(int pCapacity)
00315 {
00316
00317 #ifndef KFBX_PLUGIN
00318 K_ASSERT( pCapacity > 0 );
00319 #endif
00320
00321 if( pCapacity )
00322 {
00323 const kUInt lTempNewBlockCount = ( (kUInt) (pCapacity + KFBX_ARRAYUL_BLOCKSIZE - 1 ) / KFBX_ARRAYUL_BLOCKSIZE );
00324 const kUInt lNewBlockCount = (lTempNewBlockCount > 1 ? lTempNewBlockCount : 1);
00325
00326 int lArrayCount = GetArrayCount();
00327 int lBlockCount = GetBlockCount();
00328
00329 const kUInt lOldArraySize = lArrayCount*GetTypeSize();
00330 const kUInt lNewArraySize = lNewBlockCount*KFBX_ARRAYUL_BLOCKSIZE*GetTypeSize();
00331
00332 if (lNewBlockCount != (kUInt) lBlockCount)
00333 mBaseArray = KBaseArrayRealloc(mBaseArray, (size_t) lNewArraySize+ GetHeaderOffset() );
00334
00335 if( lNewBlockCount > (kUInt) lBlockCount ) {
00336 memset( ((char*)mBaseArray+ GetHeaderOffset() ) + lOldArraySize, 0, (size_t) (lNewArraySize-lOldArraySize) );
00337 SetArrayCount(lArrayCount);
00338 } else if (pCapacity < lArrayCount)
00339 {
00340 memset( ((char*)mBaseArray+ GetHeaderOffset() ) + pCapacity*GetTypeSize(), 0, (size_t) (lNewArraySize-pCapacity*GetTypeSize()) );
00341 SetArrayCount(pCapacity);
00342 }
00343
00344 SetBlockCount(lNewBlockCount);
00345 }
00346
00347 return GetBlockCount()*KFBX_ARRAYUL_BLOCKSIZE;
00348 }
00349
00350
00352
00353
00359 inline void SetCount (int pCount)
00360 {
00361 #ifndef KFBX_PLUGIN
00362 #ifdef _DEBUG
00363 if (pCount<0)
00364 {
00365 K_ASSERT_MSG_NOW (_T("ArrayUL : Item count can't be negative"));
00366 return ;
00367 }
00368 #endif
00369 #endif
00370 int lArrayCount = GetArrayCount();
00371 if (pCount > lArrayCount)
00372 {
00373 AddMultiple( pCount-lArrayCount);
00374 } else
00375 {
00376 SetArrayCount(pCount);
00377 }
00378 }
00379
00380 inline void Resize(int pItemCount)
00381 {
00382 #ifndef KFBX_PLUGIN
00383 K_ASSERT( pItemCount >= 0 );
00384 #endif
00385
00386 const kUInt lTempNewBlockCount = ( (kUInt) (pItemCount + KFBX_ARRAYUL_BLOCKSIZE - 1 ) / KFBX_ARRAYUL_BLOCKSIZE );
00387 const kUInt lNewBlockCount = (lTempNewBlockCount > 1 ? lTempNewBlockCount : 1);
00388
00389 int lArrayCount = GetArrayCount();
00390 int lBlockCount = GetBlockCount();
00391
00392 const kUInt lOldArraySize = lArrayCount*GetTypeSize();
00393 const kUInt lNewArraySize = lNewBlockCount*KFBX_ARRAYUL_BLOCKSIZE*GetTypeSize();
00394
00395 if (lNewBlockCount != (kUInt) lBlockCount)
00396 mBaseArray = KBaseArrayRealloc(mBaseArray, (size_t) lNewArraySize+ GetHeaderOffset() );
00397
00398 if( lNewBlockCount > (kUInt) lBlockCount )
00399 memset( ((char*)mBaseArray+ GetHeaderOffset() ) + lOldArraySize, 0, (size_t) (lNewArraySize-lOldArraySize) );
00400 else if (pItemCount < lArrayCount)
00401 memset( ((char*)mBaseArray+ GetHeaderOffset() ) + pItemCount*GetTypeSize(), 0, (size_t) (lNewArraySize-pItemCount*GetTypeSize()) );
00402
00403 SetBlockCount(lNewBlockCount);
00404 SetArrayCount(pItemCount);
00405 }
00406
00407 inline void AddMultiple(int pItemCount)
00408 {
00409 #ifndef KFBX_PLUGIN
00410 K_ASSERT( pItemCount > 0 );
00411 #endif
00412
00413 if( pItemCount )
00414 {
00415 int lArrayCount = GetArrayCount();
00416 int lBlockCount = GetBlockCount();
00417 const kUInt lTempNewBlockCount = ( (kUInt) (lArrayCount+pItemCount + KFBX_ARRAYUL_BLOCKSIZE - 1 ) / KFBX_ARRAYUL_BLOCKSIZE );
00418 const kUInt lNewBlockCount = (lTempNewBlockCount > 1 ? lTempNewBlockCount : 1);
00419
00420 const kUInt lOldArraySize = lArrayCount*GetTypeSize();
00421 const kUInt lNewArraySize = lNewBlockCount*KFBX_ARRAYUL_BLOCKSIZE*GetTypeSize();
00422
00423 #ifndef KFBX_PLUGIN
00424 K_ASSERT( lOldArraySize < lNewArraySize );
00425 #endif
00426
00427 if( lNewBlockCount > (kUInt) lBlockCount )
00428 {
00429 mBaseArray = KBaseArrayRealloc(mBaseArray, (size_t) lNewArraySize+ GetHeaderOffset() );
00430 lBlockCount = lNewBlockCount;
00431 }
00432
00433 memset( ((char*)mBaseArray+ GetHeaderOffset() ) + lOldArraySize, 0, (size_t) (lNewArraySize-lOldArraySize) );
00434 SetArrayCount ( lArrayCount + pItemCount );
00435 SetBlockCount (lBlockCount);
00436 }
00437 }
00438
00439
00440 inline int GetTypeSize() const { return mTypeSize.GetTypeSize(); }
00441
00443
00444
00445
00446
00447
00448
00450 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00451
00452 protected:
00453 inline KHeader* const GetHeader() const
00454 {
00455 return (KHeader* const )mBaseArray;
00456 }
00457 inline KHeader* GetHeader()
00458 {
00459 return (KHeader*)mBaseArray;
00460 }
00461 inline int GetHeaderOffset() const
00462 {
00463 return sizeof(KHeader);
00464 }
00465 inline int GetArrayCount() const
00466 {
00467 return GetHeader() ? GetHeader()->mArrayCount : 0;
00468 }
00469 inline void SetArrayCount(int pArrayCount)
00470 {
00471 if (GetHeader()) GetHeader()->mArrayCount=pArrayCount;
00472 }
00473 inline int GetBlockCount() const
00474 {
00475 return GetHeader() ? GetHeader()->mBlockCount : 0;
00476 }
00477 inline void SetBlockCount(int pArrayCount)
00478 {
00479 if (GetHeader()) GetHeader()->mBlockCount=pArrayCount;
00480 }
00481
00482 protected:
00483 char* mBaseArray;
00484 TypeSize mTypeSize;
00485
00486 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
00487
00488 };
00489
00490
00492 #define VC6
00493
00494 template < class Type > class KArrayTemplate : public KBaseArray< KBaseArraySizeType<Type> >
00495 {
00496 typedef KBaseArray< KBaseArraySizeType<Type> > ParentClass;
00497
00498
00499 public:
00503 inline KArrayTemplate()
00504 : ParentClass (KBaseArraySizeType<Type>())
00505 {
00506 }
00507
00509 inline KArrayTemplate(const KArrayTemplate& pArrayTemplate)
00510 : ParentClass (KBaseArraySizeType<Type>())
00511 {
00512 *this = pArrayTemplate;
00513 }
00514
00515 inline ~KArrayTemplate() {}
00516
00523 inline int InsertAt(int pIndex, Type pItem)
00524 {
00525 return ParentClass::InsertAt( pIndex,&pItem );
00526 }
00527
00532 inline Type RemoveAt(int pIndex)
00533 {
00534 Type tmpItem = GetAt(pIndex);
00535 ParentClass::RemoveAt( pIndex );
00536 return tmpItem;
00537 }
00538
00542 inline Type RemoveLast()
00543 {
00544 return RemoveAt(ParentClass::GetArrayCount()-1);
00545 }
00546
00551 inline bool RemoveIt(Type pItem)
00552 {
00553 int Index = Find (pItem);
00554 if (Index>=0)
00555 {
00556 RemoveAt (Index);
00557 return true;
00558 }
00559 return false;
00560 }
00561
00563 inline Type &operator[](int pIndex) const
00564 {
00565 #if defined(_DEBUG) && !defined(KARCH_ENV_MACOSX)
00566 if (!ParentClass::ValidateIndex( pIndex ))
00567 {
00568 return (Type &)(ParentClass::mBaseArray[(0)*sizeof(Type)+ ParentClass::GetHeaderOffset() ]);
00569 }
00570 #endif
00571 return (Type &)(ParentClass::mBaseArray[(pIndex)*sizeof(Type)+ ParentClass::GetHeaderOffset() ]);
00572 }
00573
00575 inline void SetAt(int pIndex, Type pItem)
00576 {
00577 #if defined(_DEBUG) && !defined(KARCH_ENV_MACOSX)
00578 if (!ParentClass::ValidateIndex( pIndex ))
00579 {
00580 return;
00581 }
00582 #endif
00583 GetArray()[pIndex] = pItem;
00584 }
00585
00587 inline void SetLast(Type pItem)
00588 {
00589 SetAt (ParentClass::GetArrayCount()-1, pItem);
00590 }
00591
00593 inline Type GetAt(int pIndex) const
00594 {
00595 #if defined(_DEBUG) && !defined(KARCH_ENV_MACOSX)
00596 if (!ParentClass::ValidateIndex( pIndex ))
00597 {
00598 return (Type &)(ParentClass::mBaseArray[(0)*sizeof(Type)+ ParentClass::GetHeaderOffset() ]);
00599 }
00600 #endif
00601 return (Type &)(ParentClass::mBaseArray[(pIndex)*sizeof(Type)+ ParentClass::GetHeaderOffset() ]);
00602 }
00603
00607 inline Type GetFirst() const
00608 {
00609 #ifndef KFBX_PLUGIN
00610 K_ASSERT( ParentClass::GetArrayCount() >= 1 );
00611 #endif
00612 return GetAt(0);
00613 }
00614
00618 inline Type GetLast() const
00619 {
00620 #ifndef KFBX_PLUGIN
00621 K_ASSERT( ParentClass::GetArrayCount() >= 1 );
00622 #endif
00623 return GetAt(ParentClass::GetArrayCount()-1);
00624 }
00625
00630 inline int Find(Type pItem) const
00631 {
00632 return FindAfter( -1, pItem );
00633 }
00634
00640 inline int FindAfter(int pAfterIndex, Type pItem) const
00641 {
00642 #ifndef KFBX_PLUGIN
00643 #ifdef _DEBUG
00644 if ( pAfterIndex > ParentClass::GetArrayCount() || pAfterIndex < -1 )
00645 {
00646 K_ASSERT_MSG_NOW (_T("ArrayUL : Search Begin Index out of range"));
00647 return -1;
00648 }
00649 #endif
00650 #endif
00651 int Count;
00652 for ( Count=pAfterIndex+1; Count<ParentClass::GetArrayCount(); Count++)
00653 {
00654 if (GetAt(Count)==pItem)
00655 {
00656 return Count;
00657 }
00658 }
00659 return -1;
00660 }
00661
00667 inline int FindBefore(int pBeforeIndex, Type pItem) const
00668 {
00669 #ifndef KFBX_PLUGIN
00670 #ifdef _DEBUG
00671 if ( pBeforeIndex > ParentClass::GetArrayCount() || pBeforeIndex <= 0 )
00672 {
00673 K_ASSERT_MSG_NOW (_T("ArrayUL : Search Begin Index out of range"));
00674 return -1;
00675 }
00676 #endif
00677 #endif
00678 int Count;
00679 for ( Count=pBeforeIndex-1; Count>=0; Count--)
00680 {
00681 if (GetAt(Count)==pItem)
00682 {
00683 return Count;
00684 }
00685 }
00686 return -1;
00687 }
00688
00692 inline int Add(Type pItem)
00693 {
00694 return InsertAt(ParentClass::GetArrayCount(), pItem);
00695 }
00696
00700 inline int AddUnique(Type pItem)
00701 {
00702 int lReturnIndex = Find(pItem);
00703 if (lReturnIndex == -1)
00704 {
00705 lReturnIndex = Add(pItem);
00706 }
00707 return lReturnIndex;
00708 }
00709
00713 inline void AddMultiple( kUInt pItemCount )
00714 {
00715 ParentClass::AddMultiple( pItemCount );
00716 }
00717
00718 inline void AddArray(KArrayTemplate<Type> &pArray)
00719 {
00720 int lSourceIndex, lCount = pArray.GetCount();
00721 if( lCount == 0 ) return;
00722 int lDestinationIndex = ParentClass::GetCount();
00723 AddMultiple(lCount);
00724 for( lSourceIndex = 0; lSourceIndex < lCount; lSourceIndex++)
00725 {
00726 SetAt(lDestinationIndex++, pArray[lSourceIndex]);
00727 }
00728 }
00729
00730 inline void AddArrayNoDuplicate(KArrayTemplate<Type> &pArray)
00731 {
00732 int i, lCount = pArray.GetCount();
00733 for( i = 0; i < lCount; i++)
00734 {
00735 Type lItem = pArray[i];
00736 if (Find(lItem) == -1)
00737 {
00738 Add(lItem);
00739 }
00740 }
00741 }
00742 inline void RemoveArray(KArrayTemplate<Type> &pArray)
00743 {
00744 int lRemoveIndex, lRemoveCount = pArray.GetCount();
00745 for( lRemoveIndex = 0; lRemoveIndex < lRemoveCount; lRemoveIndex++)
00746 {
00747 RemoveIt(pArray[lRemoveIndex]);
00748 }
00749 }
00750
00752 inline Type* GetArray() const
00753 {
00754 if (ParentClass::mBaseArray == NULL)
00755 return NULL;
00756
00757 return (Type*)(ParentClass::mBaseArray+ ParentClass::GetHeaderOffset()) ;
00758 }
00759
00761 inline KArrayTemplate<Type>& operator=(const KArrayTemplate<Type>& pArrayTemplate)
00762 {
00763 ParentClass::Clear();
00764
00765 int i, lCount = pArrayTemplate.GetCount();
00766
00767 for (i = 0; i < lCount; i++)
00768 {
00769 Add(pArrayTemplate[i]);
00770 }
00771
00772 return (*this);
00773 }
00774
00775 #ifdef KFBX_PLUGIN
00777 inline operator Type* ()
00778 {
00779 return GetArray();
00780 }
00781 #endif
00782 };
00783
00785
00786
00787
00788
00789
00790
00792
00793 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00794
00795 template <class Type> inline void DeleteAndClear(KArrayTemplate<Type>& Array)
00796 {
00797 kUInt lItemCount = Array.GetCount();
00798 while( lItemCount )
00799 {
00800 lItemCount--;
00801 Type& Item = (Array.operator[](lItemCount));
00802 delete Item;
00803 Item = NULL;
00804 }
00805 Array.Clear();
00806 }
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820 typedef class KFBX_DLL KArrayTemplate<int *> KArrayHkInt;
00821 typedef class KFBX_DLL KArrayTemplate<kUInt *> KArrayHkUInt;
00822 typedef class KFBX_DLL KArrayTemplate<double *> KArrayHkDouble;
00823 typedef class KFBX_DLL KArrayTemplate<float *> KArrayHkFloat;
00824 typedef class KFBX_DLL KArrayTemplate<void *> KArrayVoid;
00825 typedef class KFBX_DLL KArrayTemplate<char *> KArrayChar;
00826 typedef class KFBX_DLL KArrayTemplate<int> KArraykInt;
00827 typedef class KFBX_DLL KArrayTemplate<kUInt> KArraykUInt;
00828 typedef class KFBX_DLL KArrayTemplate<float> KArraykFloat;
00829 typedef class KFBX_DLL KArrayTemplate<double> KArraykDouble;
00830
00831 typedef class KFBX_DLL KArrayTemplate<kReference> KArrayUL;
00832
00833 #endif // #ifndef DOXYGEN_SHOULD_SKIP_THIS
00834
00835 #include <fbxfilesdk/fbxfilesdk_nsend.h>
00836
00837 #endif // FBXFILESDK_COMPONENTS_KBASELIB_KLIB_KARRAYUL_H
00838