/[escript]/trunk/ripley/src/Rectangle.cpp
ViewVC logotype

Diff of /trunk/ripley/src/Rectangle.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4585 by sshaw, Wed Dec 11 04:39:54 2013 UTC revision 4586 by jfenwick, Wed Dec 11 06:03:27 2013 UTC
# Line 4007  that ripley has. Line 4007  that ripley has.
4007  */  */
4008  escript::Data Rectangle::randomFill(long seed, const boost::python::tuple& filter) const  escript::Data Rectangle::randomFill(long seed, const boost::python::tuple& filter) const
4009  {  {
 //     if (m_mpiInfo->size!=1)  
 //     {  
 //         throw RipleyException("This type of random does not support MPI yet.");  
 //     }  
4010      if (m_numDim!=2)      if (m_numDim!=2)
4011      {      {
4012          throw RipleyException("Only 2D supported at this time.");          throw RipleyException("Only 2D supported at this time.");
# Line 4029  escript::Data Rectangle::randomFill(long Line 4025  escript::Data Rectangle::randomFill(long
4025          throw RipleyException("Radius of gaussian filter must be a positive integer.");          throw RipleyException("Radius of gaussian filter must be a positive integer.");
4026      }      }
4027      unsigned int radius=ex1();      unsigned int radius=ex1();
 #ifdef ESYS_MPI      
   
     // Need to check to see that radius would not cause the overlap to cover  
     // more than one cell (eg each rank holds 4 columns and the radius is 5).  
     // Also need to take special care with narrow cells  
       
       
     // In fact it needs to be stricter than this, if a rank has neighbours on both sides, the borders can't overlap.  
       
     // basically, 2*inset<ext[i]  
       
       
 #endif      
4028      double sigma=0.5;      double sigma=0.5;
4029      boost::python::extract<double> ex2(filter[2]);      boost::python::extract<double> ex2(filter[2]);
4030      if (!ex2.check() || (sigma=ex2())<=0)      if (!ex2.check() || (sigma=ex2())<=0)
# Line 4064  escript::Data Rectangle::randomFill(long Line 4047  escript::Data Rectangle::randomFill(long
4047          throw RipleyException("Radius of gaussian filter must be less than half the width/height of a rank");          throw RipleyException("Radius of gaussian filter must be less than half the width/height of a rank");
4048      }      }
4049            
       
       
       
4050      size_t inset=2*radius+1;      size_t inset=2*radius+1;
4051      size_t Eheight=ext[1]-2*inset;  // how high the E (shared) region is      size_t Eheight=ext[1]-2*inset;  // how high the E (shared) region is
4052      size_t Swidth=ext[0]-2*inset;      size_t Swidth=ext[0]-2*inset;
   
       
 //     size_t numpoints[2];  
 //     numpoints[0]=m_ownNE[0]+1;  
 //     numpoints[1]=m_ownNE[1]+1;  
 //     size_t padding=max((unsigned)max((m_NE[0]-m_ownNE[0])/2, (m_NE[1]-m_ownNE[1])/2), radius);  
 //     size_t width=(numpoints[0]+2*padding);   // width of one row in points  
 //     size_t height=(numpoints[1]+2*padding);  // height of one row in points  
 //     size_t dsize=width * height; // size of padded source grid  
4053            
4054      double* src=new double[ext[0]*ext[1]];      double* src=new double[ext[0]*ext[1]];
4055      esysUtils::randomFillArray(seed, src, ext[0]*ext[1]);        esysUtils::randomFillArray(seed, src, ext[0]*ext[1]);  
4056            
4057          
4058      double zz=m_mpiInfo->rank;  #ifdef ESYS_MPI    
     for (unsigned int i=0;i<ext[0]*ext[1];++i)  
     {  
         src[i]=zz*1000+i;  
     }  
       
     for (unsigned int j=0;j<ext[1];++j)  
     {  
     ostringstream oss;  
         oss << ">:" << m_mpiInfo->rank << ": ";  
     for (unsigned int i=0;i<ext[0];++i)  
     {  
         oss << src[i+j*ext[0]] << " ";  
     }  
     oss << endl;  
     cerr << oss.str();  
     }  
     // Now we need to copy the regions owned by other ranks over here    
 //#ifdef ESYS_MPI      
       
   
4059    
4060      double* SWin=new double[inset*inset];  memset(SWin, 0, inset*inset*sizeof(double));      double* SWin=new double[inset*inset];  memset(SWin, 0, inset*inset*sizeof(double));
4061      double* SEin=new double[inset*inset];  memset(SEin, 0, inset*inset*sizeof(double));      double* SEin=new double[inset*inset];  memset(SEin, 0, inset*inset*sizeof(double));
# Line 4113  escript::Data Rectangle::randomFill(long Line 4064  escript::Data Rectangle::randomFill(long
4064      double* Win=new double[inset*Eheight];  memset(Win, 0, inset*Eheight*sizeof(double));      double* Win=new double[inset*Eheight];  memset(Win, 0, inset*Eheight*sizeof(double));
4065    
4066      double* NEout=new double[inset*inset];  memset(NEout, 0, inset*inset*sizeof(double));      double* NEout=new double[inset*inset];  memset(NEout, 0, inset*inset*sizeof(double));
4067      unsigned int base=ext[0]-inset+(ext[1]-inset)*ext[0];      uint base=ext[0]-inset+(ext[1]-inset)*ext[0];
4068      for (unsigned int i=0;i<inset;++i)      for (uint i=0;i<inset;++i)
4069      {      {
4070      memcpy(NEout+inset*i, src+base, inset*sizeof(double));      memcpy(NEout+inset*i, src+base, inset*sizeof(double));
4071      base+=ext[0];      base+=ext[0];
4072      }      }
4073      double* NWout=new double[inset*inset];  memset(NWout, 0, inset*inset*sizeof(double));      double* NWout=new double[inset*inset];  memset(NWout, 0, inset*inset*sizeof(double));
4074      base=(ext[1]-inset)*ext[0];      base=(ext[1]-inset)*ext[0];
4075      for (unsigned int i=0;i<inset;++i)      for (uint i=0;i<inset;++i)
4076      {      {
4077      memcpy(NWout+inset*i, src+base, inset*sizeof(double));      memcpy(NWout+inset*i, src+base, inset*sizeof(double));
4078      base+=ext[0];      base+=ext[0];
4079      }      }
4080            
 // for (unsigned int j=0;j<inset;++j)  
 // {  
 //     ostringstream oss;  
 //     oss << "NW: ";  
 //     for (unsigned int i=0;i<inset;++i)  
 //     {  
 //         oss << NWout[i+j*inset] << " ";  
 //     }  
 //     oss << endl;  
 //     if (m_mpiInfo->rank==0)  
 //     {  
 //         cerr << oss.str();  
 //     }  
 // }  
       
       
4081      double* SEout=new double[inset*inset];  memset(SEout, 0, inset*inset*sizeof(double));      double* SEout=new double[inset*inset];  memset(SEout, 0, inset*inset*sizeof(double));
4082      base=ext[0]-inset;      base=ext[0]-inset;
4083      for (int i=0;i<inset;++i)      for (int i=0;i<inset;++i)
# Line 4152  escript::Data Rectangle::randomFill(long Line 4087  escript::Data Rectangle::randomFill(long
4087      }      }
4088      double* Nout=new double[inset*Swidth];  memset(Nout, 0, inset*Swidth*sizeof(double));      double* Nout=new double[inset*Swidth];  memset(Nout, 0, inset*Swidth*sizeof(double));
4089      base=inset+(ext[1]-inset)*ext[0];      base=inset+(ext[1]-inset)*ext[0];
4090      for (unsigned int i=0;i<inset;++i)      for (uint i=0;i<inset;++i)
4091      {      {
4092      memcpy(Nout+Swidth*i, src+base, Swidth*sizeof(double));      memcpy(Nout+Swidth*i, src+base, Swidth*sizeof(double));
4093      base+=ext[0];      base+=ext[0];
4094      }      }
4095            
       
     
       
       
       
4096      double* Eout=new double[inset*Eheight];  memset(Eout, 0, inset*Eheight*sizeof(double));      double* Eout=new double[inset*Eheight];  memset(Eout, 0, inset*Eheight*sizeof(double));
4097      base=ext[0]-inset+inset*ext[0];      base=ext[0]-inset+inset*ext[0];
4098      for (unsigned int i=0;i<Eheight;++i)      for (uint i=0;i<Eheight;++i)
4099      {      {
4100      memcpy(Eout+i*inset, src+base, inset*sizeof(double));      memcpy(Eout+i*inset, src+base, inset*sizeof(double));
4101      base+=ext[0];      base+=ext[0];
4102      }      }  
       
       
 /* for (unsigned int j=0;j<Eheight;++j)  
 {  
     ostringstream oss;  
     oss << "E: ";  
     for (unsigned int i=0;i<inset;++i)  
     {  
         oss << Eout[i+j*inset] << " ";  
     }  
     oss << endl;  
     if (m_mpiInfo->rank==0)  
     {  
         cerr << oss.str();  
     }  
 }   */    
       
       
       
 #ifdef ESYS_MPI      
   
 deliberate error to test buildbot, now with extra commit  
   
4103    
4104      MPI_Request reqs[10];      MPI_Request reqs[10];
4105      MPI_Status stats[10];      MPI_Status stats[10];
# Line 4215  deliberate error to test buildbot, now w Line 4122  deliberate error to test buildbot, now w
4122      // 12 : SE corner to SW corner (only used on the bottom edge      // 12 : SE corner to SW corner (only used on the bottom edge
4123            
4124    
 //cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << SWin << " " << SEin << " " << NWin << " "<< Sin << " "<< Win << " "<< NEout << " "<< NWout << " "  
 //<< SEout << " "  
 //<< Nout << " "  
 //<< Eout << " "  
 //<< endl;            
       
4125    
4126      int comserr=0;      int comserr=0;
4127      if (Y!=0)   // not on bottom row,      if (Y!=0)   // not on bottom row,
# Line 4228  deliberate error to test buildbot, now w Line 4129  deliberate error to test buildbot, now w
4129      if (X!=0)   // not on the left hand edge      if (X!=0)   // not on the left hand edge
4130      {      {
4131          // recv bottomleft from SW          // recv bottomleft from SW
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv SW (7) from " << (X-1)+(Y-1)*row << endl;  
4132          comserr|=MPI_Irecv(SWin, inset*inset, MPI_DOUBLE, (X-1)+(Y-1)*row, 7, m_mpiInfo->comm, reqs+(rused++));          comserr|=MPI_Irecv(SWin, inset*inset, MPI_DOUBLE, (X-1)+(Y-1)*row, 7, m_mpiInfo->comm, reqs+(rused++));
4133          swused=true;          swused=true;
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv W (10) from " <<  X-1+Y*row << endl;          
4134          comserr|=MPI_Irecv(Win, Eheight*inset, MPI_DOUBLE, X-1+Y*row, 10, m_mpiInfo->comm, reqs+(rused++));          comserr|=MPI_Irecv(Win, Eheight*inset, MPI_DOUBLE, X-1+Y*row, 10, m_mpiInfo->comm, reqs+(rused++));
4135          wused=true;          wused=true;
4136      }      }
4137      else    // on the left hand edge      else    // on the left hand edge
4138      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv SW (11) from " << (Y-1)*row  << endl;              
4139          comserr|=MPI_Irecv(SWin, inset*inset, MPI_DOUBLE, (Y-1)*row, 11, m_mpiInfo->comm, reqs+(rused++));          comserr|=MPI_Irecv(SWin, inset*inset, MPI_DOUBLE, (Y-1)*row, 11, m_mpiInfo->comm, reqs+(rused++));
4140          swused=true;          swused=true;
4141      }      }
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv S (8) from " << X+(Y-1)*row  << endl;        
4142      comserr|=MPI_Irecv(Sin, Swidth*inset, MPI_DOUBLE, X+(Y-1)*row, 8, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Irecv(Sin, Swidth*inset, MPI_DOUBLE, X+(Y-1)*row, 8, m_mpiInfo->comm, reqs+(rused++));
4143      sused=true;      sused=true;
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv SE (7) from " << X+(Y-1)*row << endl;    
4144      comserr|=MPI_Irecv(SEin, inset*inset, MPI_DOUBLE, X+(Y-1)*row, 7, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Irecv(SEin, inset*inset, MPI_DOUBLE, X+(Y-1)*row, 7, m_mpiInfo->comm, reqs+(rused++));
4145      seused=true;      seused=true;
4146    
# Line 4254  deliberate error to test buildbot, now w Line 4150  deliberate error to test buildbot, now w
4150      {      {
4151      if (X!=0)      if (X!=0)
4152      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv W (10) from " << X-1+Y*row << endl;    
4153          comserr|=MPI_Irecv(Win, Eheight*inset, MPI_DOUBLE, X-1+Y*row, 10, m_mpiInfo->comm, reqs+(rused++));          comserr|=MPI_Irecv(Win, Eheight*inset, MPI_DOUBLE, X-1+Y*row, 10, m_mpiInfo->comm, reqs+(rused++));
4154          wused=true;          wused=true;
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv NW (7) from " << X-1+Y*row << endl;      
 //      comserr|=MPI_Irecv(NWin, inset*inset, MPI_DOUBLE, X-1+Y*row, 7, m_mpiInfo->comm, reqs+(rused++));  
 //      nwused=true;  
4155          // Need to use tag 12 here because SW is coming from the East not South East          // Need to use tag 12 here because SW is coming from the East not South East
4156          comserr|=MPI_Irecv(SWin, inset*inset, MPI_DOUBLE, X-1+Y*row, 12, m_mpiInfo->comm, reqs+(rused++));          comserr|=MPI_Irecv(SWin, inset*inset, MPI_DOUBLE, X-1+Y*row, 12, m_mpiInfo->comm, reqs+(rused++));
4157          swused=true;          swused=true;
4158      }      }
4159      if (X!=(row-1))      if (X!=(row-1))
4160      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send SE (12) to " <<  X+1+(Y)*row << endl;          
4161          comserr|=MPI_Isend(SEout, inset*inset, MPI_DOUBLE, X+1+(Y)*row, 12, m_mpiInfo->comm, reqs+(rused++));            comserr|=MPI_Isend(SEout, inset*inset, MPI_DOUBLE, X+1+(Y)*row, 12, m_mpiInfo->comm, reqs+(rused++));  
4162      }      }
4163      }      }
4164            
4165      if (Y!=(m_NX[1]-1)) // not on the top row      if (Y!=(m_NX[1]-1)) // not on the top row
4166      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send N (8) to " << X+(Y+1)*row  << endl;  
4167      comserr|=MPI_Isend(Nout, inset*Swidth, MPI_DOUBLE, X+(Y+1)*row, 8, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Isend(Nout, inset*Swidth, MPI_DOUBLE, X+(Y+1)*row, 8, m_mpiInfo->comm, reqs+(rused++));
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send NE (7) to " <<  X+(Y+1)*row << endl;  
4168      comserr|=MPI_Isend(NEout, inset*inset, MPI_DOUBLE, X+(Y+1)*row, 7, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Isend(NEout, inset*inset, MPI_DOUBLE, X+(Y+1)*row, 7, m_mpiInfo->comm, reqs+(rused++));
4169      if (X!=(row-1)) // not on right hand edge      if (X!=(row-1)) // not on right hand edge
4170      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send NE (7) to " <<  X+1+(Y+1)*row << endl;              
4171          comserr|=MPI_Isend(NEout, inset*inset, MPI_DOUBLE, X+1+(Y+1)*row, 7, m_mpiInfo->comm, reqs+(rused++));          comserr|=MPI_Isend(NEout, inset*inset, MPI_DOUBLE, X+1+(Y+1)*row, 7, m_mpiInfo->comm, reqs+(rused++));
4172      }      }
4173      if (X==0)   // left hand edge      if (X==0)   // left hand edge
4174      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send NW (11) to " << (Y+1)*row << endl;      
4175          comserr|=MPI_Isend(NWout, inset*inset, MPI_DOUBLE, (Y+1)*row,11, m_mpiInfo->comm, reqs+(rused++));                comserr|=MPI_Isend(NWout, inset*inset, MPI_DOUBLE, (Y+1)*row,11, m_mpiInfo->comm, reqs+(rused++));      
4176      }        }  
4177      }      }
4178      if (X!=(row-1)) // not on right hand edge      if (X!=(row-1)) // not on right hand edge
4179      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send NE (7) to " << X+1+(Y)*row << endl;        
4180      comserr|=MPI_Isend(NEout, inset*inset, MPI_DOUBLE, X+1+(Y)*row, 7, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Isend(NEout, inset*inset, MPI_DOUBLE, X+1+(Y)*row, 7, m_mpiInfo->comm, reqs+(rused++));
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Send E (10) to " << X+1+(Y)*row << endl;      
4181      comserr|=MPI_Isend(Eout, Eheight*inset, MPI_DOUBLE, X+1+(Y)*row, 10, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Isend(Eout, Eheight*inset, MPI_DOUBLE, X+1+(Y)*row, 10, m_mpiInfo->comm, reqs+(rused++));
4182      }      }
4183      if (X!=0)      if (X!=0)
4184      {      {
 // cerr << m_mpiInfo->rank << "[" << __LINE__ << "]: " << "Recv NW (7) from " << (X-1)+Y*row << endl;    
         
4185      comserr|=MPI_Irecv(NWin, inset*inset, MPI_DOUBLE, (X-1)+Y*row, 7, m_mpiInfo->comm, reqs+(rused++));      comserr|=MPI_Irecv(NWin, inset*inset, MPI_DOUBLE, (X-1)+Y*row, 7, m_mpiInfo->comm, reqs+(rused++));
4186      nwused=true;      nwused=true;
4187                
# Line 4306  deliberate error to test buildbot, now w Line 4189  deliberate error to test buildbot, now w
4189      }      }
4190            
4191      if (!comserr)      if (!comserr)
4192      {      {    
 //cerr << rused << ": " <<   m_mpiInfo->rank << "[" << __LINE__ << "]\n";          
4193          comserr=MPI_Waitall(rused, reqs, stats);          comserr=MPI_Waitall(rused, reqs, stats);
4194      }      }
4195    
# Line 4326  deliberate error to test buildbot, now w Line 4208  deliberate error to test buildbot, now w
4208      if (swused)      if (swused)
4209      {      {
4210      base=0;      base=0;
4211      for (unsigned int i=0;i<inset;++i)      for (uint i=0;i<inset;++i)
4212      {      {
4213          memcpy(src+base, SWin+i*inset, inset*sizeof(double));          memcpy(src+base, SWin+i*inset, inset*sizeof(double));
4214          base+=ext[0];          base+=ext[0];
# Line 4335  deliberate error to test buildbot, now w Line 4217  deliberate error to test buildbot, now w
4217      if (seused)      if (seused)
4218      {      {
4219          base=ext[0]-inset;          base=ext[0]-inset;
4220      for (unsigned int i=0;i<inset;++i)      for (uint i=0;i<inset;++i)
4221      {      {
4222          memcpy(src+base, SEin+i*inset, inset*sizeof(double));          memcpy(src+base, SEin+i*inset, inset*sizeof(double));
4223          base+=ext[0];          base+=ext[0];
# Line 4344  deliberate error to test buildbot, now w Line 4226  deliberate error to test buildbot, now w
4226      if (nwused)      if (nwused)
4227      {      {
4228          base=(ext[1]-inset)*ext[0];          base=(ext[1]-inset)*ext[0];
4229      for (unsigned int i=0;i<inset;++i)      for (uint i=0;i<inset;++i)
4230      {      {
4231          memcpy(src+base, NWin+i*inset, inset*sizeof(double));          memcpy(src+base, NWin+i*inset, inset*sizeof(double));
4232          base+=ext[0];          base+=ext[0];
# Line 4353  deliberate error to test buildbot, now w Line 4235  deliberate error to test buildbot, now w
4235      if (sused)      if (sused)
4236      {      {
4237         base=inset;         base=inset;
4238         for (unsigned int i=0;i<inset;++i)         for (uint i=0;i<inset;++i)
4239         {         {
4240         memcpy(src+base, Sin+i*Swidth, Swidth*sizeof(double));         memcpy(src+base, Sin+i*Swidth, Swidth*sizeof(double));
4241         base+=ext[0];         base+=ext[0];
# Line 4362  deliberate error to test buildbot, now w Line 4244  deliberate error to test buildbot, now w
4244      if (wused)      if (wused)
4245      {      {
4246      base=inset*ext[0];      base=inset*ext[0];
4247      for (unsigned int i=0;i<Eheight;++i)      for (uint i=0;i<Eheight;++i)
4248      {      {
4249          memcpy(src+base, Win+i*inset, inset*sizeof(double));          memcpy(src+base, Win+i*inset, inset*sizeof(double));
4250          base+=ext[0];          base+=ext[0];
4251      }      }
4252                
4253      }      }
     for (unsigned int j=0;j<ext[1];++j)  
     {  
     ostringstream oss;  
         oss << "<;" << m_mpiInfo->rank << "; ";  
     for (unsigned int i=0;i<ext[0];++i)  
     {  
         oss << src[i+j*ext[0]] << " ";  
     }  
     oss << endl;  
     cerr << oss.str();  
     }      
       
4254            
4255      delete[] SWin;      delete[] SWin;
4256      delete[] SEin;      delete[] SEin;
# Line 4393  deliberate error to test buildbot, now w Line 4263  deliberate error to test buildbot, now w
4263      delete[] SEout;      delete[] SEout;
4264      delete[] Nout;      delete[] Nout;
4265      delete[] Eout;      delete[] Eout;
       
       
       
       
4266  #endif      #endif    
     // Lets call that done for now  
4267      escript::FunctionSpace fs(getPtr(), getContinuousFunctionCode());      escript::FunctionSpace fs(getPtr(), getContinuousFunctionCode());
4268      escript::Data resdat(0, escript::DataTypes::scalarShape, fs , true);      escript::Data resdat(0, escript::DataTypes::scalarShape, fs , true);
4269      // don't need to check for exwrite because we just made it      // don't need to check for exwrite because we just made it
4270      escript::DataVector& dv=resdat.getExpandedVectorReference();      escript::DataVector& dv=resdat.getExpandedVectorReference();
4271      double* convolution=get2DGauss(radius, sigma);      double* convolution=get2DGauss(radius, sigma);
4272      for (size_t y=0;y<(m_ownNE[1]+1);++y)          for (size_t y=0;y<(internal[1]);++y)    
4273      {      {
4274          for (size_t x=0;x<(m_ownNE[0]+1);++x)          for (size_t x=0;x<(internal[0]);++x)
4275      {          {    
4276          dv[x+y*(m_ownNE[0]+1)]=Convolve2D(convolution, src, x+radius, y+radius, radius, ext[0]);          dv[x+y*(internal[0])]=Convolve2D(convolution, src, x+radius, y+radius, radius, ext[0]);
4277            
4278      }      }
4279      }      }
4280      delete[] convolution;      delete[] convolution;
4281        delete[] src;
4282      return resdat;      return resdat;
4283  }  }
4284    

Legend:
Removed from v.4585  
changed lines
  Added in v.4586

  ViewVC Help
Powered by ViewVC 1.1.26