Changeset 499 in 3DVCSoftware


Ignore:
Timestamp:
27 Jun 2013, 00:45:09 (11 years ago)
Author:
zhang
Message:

Changes include: DV-MVP(H_3D_IDV), TMVP merging candidate(H_3D_TMVP, target reference index changes, scaling based on view order index) and cleanups (H_3D_CLEANUPS)

Location:
branches/HTM-DEV-0.3-dev2/source
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • branches/HTM-DEV-0.3-dev2/source/App/TAppEncoder/TAppEncCfg.cpp

    r486 r499  
    11001100     0.753550, 0.800000 
    11011101  };
     1102#if H_3D_CLEANUPS
     1103  if ( m_bUseVSO && m_bVSOLSTable )
     1104#else
    11021105  if ( m_bVSOLSTable )
     1106#endif
    11031107  {
    11041108    Int firstDepthLayer = -1;
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibCommon/TComDataCU.cpp

    r487 r499  
    24632463  Int     iPosLeftAbove[2]  = {-1, -1};
    24642464
    2465   //Notes from QC: DvMCP related variables. 
    2466   //acPdmMv[0].m_bDvMcp = acPdmMv[1].m_bDvMcp = acPdmMv[2].m_bDvMcp = acPdmMv[3].m_bDvMcp = false;
    24672465
    24682466  DisInfo cDisInfo;
     
    24972495        //clipMv(cMvPred);
    24982496        //pcMvFieldNeighbours[iCount<<1].setMvField(cMvPred,pcMvFieldNeighbours[iCount<<1].getRefIdx());
     2497#if H_3D_CLEANUPS //Notes from QC: for BVSP coded blocks, the reference index shall not be equal to -1 due to the adoption of JCT3V-D0191
     2498        pcMvFieldNeighbours[iCount<<1].setMvField(cMvPred,pcMvFieldNeighbours[iCount<<1].getRefIdx());
     2499#else
    24992500        if (pcMvFieldNeighbours[iCount<<1].getRefIdx()<0)
    25002501        {
     
    25082509          }
    25092510        }
    2510 
     2511#endif
    25112512      }
    25122513     
     
    25242525          //clipMv(cMvPred);
    25252526          //pcMvFieldNeighbours[(iCount<<1)+1].setMvField(cMvPred,pcMvFieldNeighbours[(iCount<<1)+1].getRefIdx());
     2527#if H_3D_CLEANUPS
     2528          pcMvFieldNeighbours[(iCount<<1)+1].setMvField(cMvPred,pcMvFieldNeighbours[(iCount<<1)+1].getRefIdx());
     2529#else
    25262530          if (pcMvFieldNeighbours[(iCount<<1)+1].getRefIdx()<0)
    25272531          {
     
    25352539            }
    25362540          }
    2537 
     2541#endif
    25382542        }
    25392543      }
    2540 
     2544#if !H_3D_CLEANUPS
    25412545      if (!((pcMvFieldNeighbours[iCount<<1].getRefIdx()<0 && !getSlice()->isInterB())
    25422546        || (pcMvFieldNeighbours[iCount<<1].getRefIdx()<0 && pcMvFieldNeighbours[(iCount<<1)+1].getRefIdx()<0 && getSlice()->isInterB())))
    25432547      {
     2548#endif
     2549#if H_3D_IDV
     2550        pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2551        pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2552#endif
    25442553        if ( mrgCandIdx == iCount )
    25452554        {
     
    25472556        }
    25482557        iCount ++;
     2558#if !H_3D_CLEANUPS
    25492559      }
    25502560      else
     
    25522562        assert(0);
    25532563      }
     2564#endif
    25542565    }
    25552566  }
     
    25632574   
    25642575  Int iPdmInterDir;
     2576#if H_3D_CLEANUPS
     2577  if( iPdmDir[0] )
     2578#else
    25652579  if( iPdmDir[0] && ivMvPredFlag )
     2580#endif
    25662581  {
    25672582    abCandIsInter        [ iCount ] = true;
     
    25732588      pcMvFieldNeighbours[ iCount<<1    ].setMvField( acPdmMv[ 0 ], aiPdmRefIdx[ 0 ] );
    25742589    }
    2575 
    25762590    if( ( iPdmInterDir & 2 ) == 2 )
    25772591    {
     
    25842598    }
    25852599    iCount ++;
    2586   } 
     2600  }
     2601#if H_3D_CLEANUPS
     2602  // early termination
     2603  if (iCount == getSlice()->getMaxNumMergeCand())
     2604  {
     2605    return;
     2606  }
     2607#endif
    25872608#endif
    25882609
     
    26462667      bLeftAvai = true;
    26472668      iPosLeftAbove[0] = iCount;
    2648 
     2669#if H_3D_IDV
     2670      pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2671      pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2672#endif
    26492673      if ( mrgCandIdx == iCount )
    26502674      {
     
    27072731    {
    27082732      iPosLeftAbove[1] = iCount;
    2709 
     2733#if H_3D_IDV
     2734      pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2735      pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2736#endif
    27102737      if ( mrgCandIdx == iCount )
    27112738      {
     
    27462773      pcCUAboveRight->getMvField( pcCUAboveRight, uiAboveRightPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    27472774    }
     2775#if H_3D_IDV
     2776    pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2777    pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2778#endif
    27482779    if ( mrgCandIdx == iCount )
    27492780    {
     
    27592790
    27602791#if H_3D_IV_MERGE
     2792#if H_3D_CLEANUPS
     2793  if( iPdmDir[1] )
     2794#else
    27612795  if(ivMvPredFlag && iPdmDir[1] )
     2796#endif
    27622797  {
    27632798    assert(iCount < getSlice()->getMaxNumMergeCand());
     
    27922827    if(!bRemoveSpa)
    27932828    {
     2829#if H_3D_IDV
     2830      pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2831      pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2832#endif
    27942833      if ( mrgCandIdx == iCount )
    27952834        return;
     
    28232862      pcCULeftBottom->getMvField( pcCULeftBottom, uiLeftBottomPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    28242863    }
     2864#if H_3D_IDV
     2865    pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2866    pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2867#endif
    28252868    if ( mrgCandIdx == iCount )
    28262869    {
     
    28552898        pcCUAboveLeft->getMvField( pcCUAboveLeft, uiAboveLeftPartIdx, REF_PIC_LIST_1, pcMvFieldNeighbours[(iCount<<1)+1] );
    28562899      }
     2900#if H_3D_IDV
     2901      pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     2902      pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     2903#endif
    28572904      if ( mrgCandIdx == iCount )
    28582905      {
     
    29322979      pcMvFieldNeighbours[ 2 * uiArrayAddr ].setMvField( cColMv, iRefIdx );
    29332980    }
    2934    
     2981
    29352982    if ( getSlice()->isInterB() )
    29362983    {
     2984#if H_3D_TMVP
     2985      iRefIdx = 0;
     2986#endif
    29372987      bExistMV = uiLCUIdx >= 0 && xGetColMVP( REF_PIC_LIST_1, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx);
    29382988      if( bExistMV == false )
     
    29513001      puhInterDirNeighbours[uiArrayAddr] = dir;
    29523002      abCandIsInter[uiArrayAddr] = true;
    2953 
     3003#if H_3D_IDV
     3004      pcMvFieldNeighbours[iCount<<1    ].getMv().setIDVFlag (false);
     3005      pcMvFieldNeighbours[(iCount<<1)+1].getMv().setIDVFlag (false);
     3006#endif
    29543007      if ( mrgCandIdx == iCount )
    29553008      {
     
    32583311      }
    32593312    }
    3260     if ( uiLCUIdx >= 0 && xGetColMVP( eRefPicList, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx_Col ) )
     3313    if ( uiLCUIdx >= 0 && xGetColMVP( eRefPicList, uiLCUIdx, uiAbsPartAddr, cColMv, iRefIdx_Col
     3314#if H_3D_TMVP
     3315         , 0
     3316#endif
     3317    ) )
    32613318    {
    32623319      pInfo->m_acMvCand[pInfo->iN++] = cColMv;
     
    32673324      UInt uiCurLCUIdx = getAddr();
    32683325      xDeriveCenterIdx( uiPartIdx, uiPartIdxCenter );
    3269       if (xGetColMVP( eRefPicList, uiCurLCUIdx, uiPartIdxCenter,  cColMv, iRefIdx_Col ))
     3326      if (xGetColMVP( eRefPicList, uiCurLCUIdx, uiPartIdxCenter,  cColMv, iRefIdx_Col
     3327#if H_3D_TMVP
     3328         , 0
     3329#endif
     3330      ))
    32703331      {
    32713332        pInfo->m_acMvCand[pInfo->iN++] = cColMv;
     
    35823643 * \returns Bool
    35833644 */
    3584 Bool TComDataCU::xGetColMVP( RefPicList eRefPicList, Int uiCUAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx )
     3645Bool TComDataCU::xGetColMVP( RefPicList eRefPicList, Int uiCUAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx
     3646#if H_3D_TMVP
     3647  , Bool bMRG
     3648#endif
     3649  )
    35853650{
    35863651  UInt uiAbsPartAddr = uiPartUnitIdx;
     
    36303695  if ( bIsCurrRefLongTerm != bIsColRefLongTerm )
    36313696  {
    3632     return false;
     3697#if H_3D_TMVP
     3698    Int iAlterRefIdx  = m_pcSlice->getAlterRefIdx(eRefPicList);
     3699    if(bMRG && iAlterRefIdx > 0)
     3700    {
     3701      riRefIdx = iAlterRefIdx;
     3702      bIsCurrRefLongTerm = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getIsLongTerm();
     3703      iCurrRefPOC = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getPOC();
     3704      assert(bIsCurrRefLongTerm == bIsColRefLongTerm);
     3705    }
     3706    else
     3707    {
     3708#endif
     3709      return false;
     3710#if H_3D_TMVP
     3711    }
     3712#endif
    36333713  }
    36343714
    36353715  if ( bIsCurrRefLongTerm || bIsColRefLongTerm )
    36363716  {
    3637     rcMv = cColMv;
     3717#if H_3D_TMVP
     3718     Int iCurrViewId    = m_pcSlice->getViewIndex ();
     3719     Int iCurrRefViewId = m_pcSlice->getRefPic(eRefPicList, riRefIdx)->getViewIndex ();
     3720     Int iColViewId     = pColCU->getSlice()->getViewIndex();
     3721     Int iColRefViewId  = pColCU->getSlice()->getRefPic( eColRefPicList, pColCU->getCUMvField(eColRefPicList)->getRefIdx(uiAbsPartAddr))->getViewIndex();
     3722     iScale = xGetDistScaleFactor( iCurrViewId, iCurrRefViewId, iColViewId, iColRefViewId );
     3723     if ( iScale != 4096 )
     3724     {
     3725        rcMv = cColMv.scaleMv( iScale );
     3726     }
     3727     else
     3728     {
     3729#endif
     3730       rcMv = cColMv;
     3731#if H_3D_TMVP
     3732    }
     3733#endif
    36383734  }
    36393735  else
     
    43544450          clipMv( cDispVec );
    43554451          pDInfo->m_acNBDV = cDispVec;
     4452#if H_3D_CLEANUPS
     4453          pDInfo->m_aVIdxCan = cIDVInfo.m_aVIdxCan[iList][ curPos ];
     4454          assert(pDInfo->m_aVIdxCan == 0); //Notes from QC: only works for CTC
     4455#else
    43564456          pDInfo->m_aVIdxCan = 0;
     4457#endif
    43574458#if H_3D_NBDV_REF
     4459#if H_3D_CLEANUPS
     4460          TComPic* picDepth = getSlice()->getIvPic( true, pDInfo->m_aVIdxCan );
     4461#else
    43584462          TComPic* picDepth = getSlice()->getIvPic( true, 0 );
     4463#endif
    43594464          assert(picDepth!=NULL);
    43604465
    43614466          if (picDepth && bDepthRefine)
     4467#if H_3D_CLEANUPS
     4468            estimateDVFromDM (pDInfo->m_aVIdxCan, uiPartIdx, picDepth, uiPartAddr, &cDispVec);
     4469#else
    43624470            estimateDVFromDM(0, uiPartIdx, picDepth, uiPartAddr, &cDispVec ); // from base view
    4363 
     4471#endif
    43644472          pDInfo->m_acDoNBDV = cDispVec;
    43654473         
     
    44844592
    44854593          UInt uiPartIdx = 0;   //Notes from MTK: Please confirm that using 0 as partition index and partition address is correct for CU-level DoNBDV
    4486           UInt uiPartAddr = 0;
     4594          UInt uiPartAddr = 0;  //QC: confirmed
    44874595
    44884596          if (picDepth && bDepthRefine)
     
    46154723{
    46164724  TComSlice*    pcSlice         = getSlice (); 
    4617 
     4725#if H_3D_CLEANUPS //Notes from QC: to be aligned with the spec.
     4726  Int iViewIndex = pDInfo->m_aVIdxCan;
     4727#else
    46184728  Bool valid     = false;
     4729
    46194730  Int iViewIndex = 0;
    46204731
     
    46424753  if (!valid)
    46434754    return false;
    4644 
     4755#endif
    46454756  //--- get base CU/PU and check prediction mode ---
    46464757  TComPic*    pcBasePic   = pcSlice->getIvPic( false, iViewIndex );
     
    46754786
    46764787  Bool abPdmAvailable[4] = {false, false, false, false};
     4788#if H_3D_IDV
     4789  for( Int i = 0; i < 4; i++)
     4790  {
     4791    pacPdmMv[i].setIDVFlag   (false);
     4792  }
     4793#endif
    46774794  if(!( pcBaseCU->getPredictionMode( iBaseAbsPartIdx ) == MODE_INTRA ))
    46784795  {
     
    46994816                abPdmAvailable[ uiCurrRefListId ] = true;
    47004817                TComMv cMv(cBaseMvField.getHor(), cBaseMvField.getVer());
    4701 
    4702                 //                  cMv.m_bDvMcp = true;
    4703                 //                  cMv.m_iDvMcpDispX = pDInfo->m_acMvCand[0].getHor();                 
    4704 
     4818#if H_3D_IDV
     4819                cMv.setIDVFlag   (true);
     4820                cMv.setIDVHor    (cDv.getHor());                 
     4821                cMv.setIDVVer    (cDv.getVer()); 
     4822#endif
    47054823                clipMv( cMv );
    47064824                paiPdmRefIdx  [ uiCurrRefListId ] = iPdmRefIdx;
     
    47164834  }
    47174835  availableMcDc[0] = ( abPdmAvailable[0] ? 1 : 0 ) + ( abPdmAvailable[1] ? 2 : 0 );
    4718 
    47194836  for( Int iRefListId = 0; iRefListId < 2 ; iRefListId++ )
    47204837  {
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibCommon/TComDataCU.h

    r486 r499  
    213213
    214214  Void          deriveRightBottomIdx        ( UInt uiPartIdx, UInt& ruiPartIdxRB );
    215   Bool          xGetColMVP( RefPicList eRefPicList, Int uiCUAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx );
     215  Bool          xGetColMVP( RefPicList eRefPicList, Int uiCUAddr, Int uiPartUnitIdx, TComMv& rcMv, Int& riRefIdx
     216#if H_3D_TMVP
     217  ,
     218  Bool bMRG = true
     219#endif
     220  );
    216221 
    217222  /// compute required bits to encode MVD (used in AMVP)
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibCommon/TComMv.h

    r455 r499  
    9494  Void  setHor    ( Short i )                   { m_iHor = i;                               }
    9595  Void  setVer    ( Short i )                   { m_iVer = i;                               }
    96   Void  setZero   ()                            { m_iHor = m_iVer = 0;  }
     96  Void  setZero   ()                            { m_iHor = m_iVer = 0; 
     97 #if H_3D_NBDV
     98   m_bIDV = false; m_iIDVHor = m_iIDVVer = 0;
     99#endif
     100  }
    97101#if H_3D_NBDV
    98102  Void   setIDVHor  (Short i)                    {m_iIDVHor = i;}
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibCommon/TComSlice.cpp

    r486 r499  
    221221  m_numEntryPointOffsets = 0;
    222222  m_enableTMVPFlag = true;
     223#if H_3D_TMVP
     224  m_aiAlterRefIdx[0]                  = -1;
     225  m_aiAlterRefIdx[1]                  = -1;
     226#endif
    223227}
    224228
     
    699703}
    700704#if H_3D
     705#if H_3D_TMVP
     706Void TComSlice::generateAlterRefforTMVP()
     707{
     708  for ( UInt uiRefListIdx = 0; uiRefListIdx < 2; uiRefListIdx++ )
     709  {       
     710    if ( this->getNumRefIdx( RefPicList( uiRefListIdx ) ) == 0)
     711        continue;
     712
     713    Bool bZeroIdxLtFlag = this->getRefPic(RefPicList(uiRefListIdx), 0)->getIsLongTerm();
     714    for(Int i = 1; i < this->getNumRefIdx(RefPicList(uiRefListIdx)); i++ )
     715    {
     716      if ( ( bZeroIdxLtFlag && !this->getRefPic(RefPicList(uiRefListIdx), i)->getIsLongTerm() ) ||
     717           (!bZeroIdxLtFlag &&  this->getRefPic(RefPicList(uiRefListIdx), i)->getIsLongTerm() ) )
     718      {
     719        this->setAlterRefIdx(RefPicList(uiRefListIdx),i);
     720        break;
     721      }
     722    }
     723  }
     724}
     725#endif
    701726Void TComSlice::setCamparaSlice( Int** aaiScale, Int** aaiOffset )
    702727
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibCommon/TComSlice.h

    r486 r499  
    15061506  Bool       m_isDepth;
    15071507  Int        m_aaiCodedScale [2][MAX_NUM_LAYERS];
    1508   Int        m_aaiCodedOffset[2][MAX_NUM_LAYERS]; 
     1508  Int        m_aaiCodedOffset[2][MAX_NUM_LAYERS];
     1509#if H_3D_TMVP
     1510  Int        m_aiAlterRefIdx   [2];
     1511#endif
    15091512#if H_3D_GEN
    15101513  TComPic*   m_ivPicsCurrPoc [2][MAX_NUM_LAYERS]; 
     
    17791782  Int       getViewId             ()                 { return m_viewId;     }
    17801783#if H_3D
     1784#if H_3D_TMVP
     1785  Void      generateAlterRefforTMVP ();   
     1786  Void      setAlterRefIdx          ( RefPicList e, Int i ) { m_aiAlterRefIdx[e]    = i;      }
     1787  Int       getAlterRefIdx          ( RefPicList e )        { return  m_aiAlterRefIdx[e];     }
     1788#endif
    17811789  Void      setViewIndex          ( Int viewIndex )  { m_viewIndex = viewIndex;   }
    17821790  Int       getViewIndex          ()                 { return m_viewIndex;     }
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibCommon/TypeDef.h

    r486 r499  
    7878                                              // LGE_WVSO_A0119
    7979#define H_3D_NBDV                         1   // Neighboring block disparity derivation
    80                                               // JCT3V-A0097
     80                                              // QC_JCT3V-A0097
    8181                                              // LGE_DVMCP_A0126
    8282                                              // LGE_DVMCP_MEM_REDUCTION_B0135     
     
    8888                                              // QC_CU_NBDV_D0181
    8989                                              // SEC_DEFAULT_DV_D0112
     90#if H_3D_NBDV
     91#define H_3D_IDV                          1   // LGE_DVMCP_A0126  QC note: this macro will be removed after merging to dev2a
    9092#define H_3D_NBDV_REF                     1   // Depth oriented neighboring block disparity derivation
    9193                                              // MTK_D0156
    9294                                              // MERL_VSP_NBDV_RefVId_Fix_D0166
     95#endif
    9396#define H_3D_VSP                          0   // Depth oriented neighboring block disparity derivation
    9497
     
    101104                                              // QC_AMVP_MRG_UNIFY_IVCAN_C0051     
    102105                                              // TEXTURE MERGING CANDIDATE     , JCT3V-C0137
     106#define H_3D_TMVP                         1   // QC_TMVP_C0047
     107                                              // Sony_M23639
    103108#define H_3D_GEN                          1   // Some general changes can be removed after merge
     109#define H_3D_CLEANUPS                     1
    104110#endif
    105111
     
    121127////   ****** Neighbouring block-based Disparity Vector  *********
    122128#if H_3D_NBDV
     129#if H_3D_CLEANUPS
     130#define DVFROM_LEFTBELOW                  0
     131#define DVFROM_LEFT                       1
     132#define DVFROM_ABOVERIGHT                 2
     133#define DVFROM_ABOVE                      3
     134#define DVFROM_ABOVELEFT                  4
     135#define IDV_CANDS                         5
     136#else
    123137#define IDV_CANDS                         6
    124138#define DVFROM_LEFTBELOW                  1
     
    127141#define DVFROM_ABOVE                      4
    128142#define DVFROM_ABOVELEFT                  5
     143#endif
    129144#endif
    130145/////////////////////////////////////////////////////////////////////////////////////////
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibDecoder/TDecTop.cpp

    r479 r499  
    959959    }
    960960#endif
     961#if  H_3D_TMVP
     962    if(pcSlice->getLayerId())
     963      pcSlice->generateAlterRefforTMVP();
     964#endif
    961965  }
    962966
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibEncoder/TEncGOP.cpp

    r486 r499  
    778778    pcSlice->generateCombinedList();
    779779#endif
    780 
     780#if H_3D_TMVP
     781    if(pcSlice->getLayerId())
     782      pcSlice->generateAlterRefforTMVP();
     783#endif
    781784    if (m_pcEncTop->getTMVPModeId() == 2)
    782785    {
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibExtractor/TExtrTop.cpp

    r446 r499  
    115115}
    116116#endif
     117
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibRenderer/TRenImagePlane.cpp

    r446 r499  
    529529template class TRenImagePlanePart<Int>;
    530530#endif // H_3D
     531
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibRenderer/TRenInterpFilter.cpp

    r446 r499  
    5151
    5252#endif // H_3D
     53
  • branches/HTM-DEV-0.3-dev2/source/Lib/TLibRenderer/TRenTop.cpp

    r446 r499  
    22272227}
    22282228#endif // H_3D
     2229
Note: See TracChangeset for help on using the changeset viewer.