SNAP Library 2.0, Developer Reference
2013-05-13 16:33:57
SNAP, a general purpose, high performance system for analysis and manipulation of large networks
|
00001 00002 // Url-Lexical-Chars 00003 class TUrlLxChDef{ 00004 private: 00005 TBoolV IsLoAlphaV, IsHiAlphaV, IsAlphaV; 00006 TBoolV IsDigitV, IsSafeV, IsExtraV; 00007 TBoolV IsNationalV, IsPunctuationV; 00008 TBoolV IsReservedV, IsHexV; 00009 TBoolV IsUnreservedV, IsUCharV, IsXCharV; 00010 TBoolV IsSchemeV, IsHostV, IsHSegmentV; 00011 void InclCh(TBoolV& BoolV, const char& Ch); 00012 void InclStr(TBoolV& BoolV, const TStr& Str); 00013 void InclBoolV(TBoolV& BoolV, const TBoolV& OrBoolV); 00014 public: 00015 static const char EofCh; 00016 static const char EscCh; 00017 TUrlLxChDef(); 00018 00019 bool IsDigitCh(const char& Ch) const {return (Ch>=0)&&IsDigitV[Ch];} 00020 bool IsSchemeCh(const char& Ch) const {return (Ch>=0)&&IsSchemeV[Ch];} 00021 bool IsHostCh(const char& Ch) const {return (Ch>=0)&&IsHostV[Ch];} 00022 bool IsHSegmentCh(const char& Ch) const { 00023 return (Ch<0)||((Ch>=0)&&IsHSegmentV[Ch]);} 00024 }; 00025 const char TUrlLxChDef::EofCh=0; 00026 const char TUrlLxChDef::EscCh='%'; 00027 00028 void TUrlLxChDef::InclCh(TBoolV& BoolV, const char& Ch){BoolV[Ch]=true;} 00029 00030 void TUrlLxChDef::InclStr(TBoolV& BoolV, const TStr& Str){ 00031 for (int CC=0; CC<Str.Len(); CC++){BoolV[Str.GetCh(CC)]=true;}} 00032 00033 void TUrlLxChDef::InclBoolV(TBoolV& BoolV, const TBoolV& OrBoolV){ 00034 for (int BoolN=0; BoolN<BoolV.Len(); BoolN++){ 00035 BoolV[BoolN]=BoolV[BoolN]||OrBoolV[BoolN];}} 00036 00037 TUrlLxChDef::TUrlLxChDef(): 00038 IsLoAlphaV(TCh::Vals), IsHiAlphaV(TCh::Vals), IsAlphaV(TCh::Vals), 00039 IsDigitV(TCh::Vals), IsSafeV(TCh::Vals), IsExtraV(TCh::Vals), 00040 IsNationalV(TCh::Vals), IsPunctuationV(TCh::Vals), 00041 IsReservedV(TCh::Vals), IsHexV(TCh::Vals), 00042 IsUnreservedV(TCh::Vals), IsUCharV(TCh::Vals), IsXCharV(TCh::Vals), 00043 IsSchemeV(TCh::Vals), IsHostV(TCh::Vals), IsHSegmentV(TCh::Vals){ 00044 00045 InclStr(IsLoAlphaV, "abcdefghijklmnopqrstuvwxyz"); 00046 InclStr(IsHiAlphaV, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 00047 InclBoolV(IsAlphaV, IsLoAlphaV); InclBoolV(IsAlphaV, IsHiAlphaV); 00048 InclStr(IsDigitV, "0123456789"); 00049 InclStr(IsSafeV, "$-_.+"); 00050 InclStr(IsExtraV, "!*'(),"); 00051 InclStr(IsNationalV, "{}|\\^~[]`"); 00052 InclStr(IsPunctuationV, "<>#%\""); 00053 InclStr(IsReservedV, ";/?:@&="); 00054 InclBoolV(IsHexV, IsDigitV); InclStr(IsHexV, "ABCDEFabcdef"); 00055 00056 InclBoolV(IsUnreservedV, IsAlphaV); InclBoolV(IsUnreservedV, IsDigitV); 00057 InclBoolV(IsUnreservedV, IsSafeV); InclBoolV(IsUnreservedV, IsExtraV); 00058 00059 InclBoolV(IsUCharV, IsUnreservedV); InclStr(IsUCharV, TStr(EscCh)); 00060 00061 InclBoolV(IsXCharV, IsUnreservedV); InclBoolV(IsXCharV, IsReservedV); 00062 InclStr(IsXCharV, TStr(EscCh)); 00063 00064 InclBoolV(IsSchemeV, IsAlphaV); InclBoolV(IsSchemeV, IsDigitV); 00065 InclStr(IsSchemeV, "+-."); 00066 00067 InclBoolV(IsHostV, IsAlphaV); InclBoolV(IsHostV, IsDigitV); 00068 InclStr(IsHostV, "-_"); 00069 00070 InclBoolV(IsHSegmentV, IsUCharV); InclStr(IsHSegmentV, ";:@&="); 00071 InclBoolV(IsHSegmentV, IsNationalV); InclStr(IsHSegmentV, " "); 00072 } 00073 00075 // Url-Lexical 00076 class TUrlLx{ 00077 private: 00078 static const char EofCh; 00079 TChA Bf; 00080 int BfC; 00081 public: 00082 static const TUrlLxChDef ChDef; 00083 TUrlLx(const TStr& _Str): Bf(_Str), BfC(0){} 00084 bool Eof() const {return BfC==Bf.Len();}; 00085 char GetCh(){if (Eof()){return EofCh;} else {return Bf[BfC++];}} 00086 char PeekCh() const {if (Eof()){return EofCh;} else {return Bf[BfC];}} 00087 char GetCh(const char& Ch){EAssertR(GetCh()==Ch, ""); return Ch;} 00088 TStr GetStr(const TStr& Str){ 00089 for (int ChN=0; ChN<Str.Len(); ChN++){GetCh(Str[ChN]);} return Str;} 00090 const char* GetStr(const char *Str){ 00091 int Len = (int) strlen(Str); 00092 for (int ChN=0; ChN<Len; ChN++){GetCh(Str[ChN]);} 00093 return Str; 00094 } 00095 00096 bool IsSchemeCh() const {return ChDef.IsSchemeCh(PeekCh());} 00097 char GetSchemeCh(){EAssertR(IsSchemeCh(), ""); return GetCh();} 00098 bool IsDigitCh() const {return ChDef.IsDigitCh(PeekCh());} 00099 char GetDigitCh(){EAssertR(IsDigitCh(), ""); return GetCh();} 00100 bool IsHSegmentCh() const {return ChDef.IsHSegmentCh(PeekCh());} 00101 char GetHSegmentCh(){EAssertR(IsHSegmentCh(), ""); return GetCh();} 00102 TStr GetToCh(const char& Ch=TUrlLxChDef::EofCh){TChA Str; 00103 while ((PeekCh()!=EofCh)&&(PeekCh()!=Ch)){Str+=GetCh();} return Str;} 00104 00105 TStr GetScheme(){TChA Str; 00106 Str+=GetSchemeCh(); while (IsSchemeCh()){Str+=GetCh();} 00107 Str.ToLc(); return Str;} 00108 TStr GetHost(); 00109 TStr GetDigits(){TChA Str; 00110 do {Str+=GetDigitCh();} while (IsDigitCh()); return Str;} 00111 TStr GetHostPort(TStr& HostNm, TStr& PortStr, int& PortN); 00112 TStr GetHPath(TStrV& PathSegV); 00113 TStr GetSearch(){return GetToCh('#');} 00114 }; 00115 00116 const TUrlLxChDef TUrlLx::ChDef; 00117 const char TUrlLx::EofCh=TUrlLxChDef::EofCh; 00118 00119 TStr TUrlLx::GetHost(){TChA Str; 00120 EAssertR(ChDef.IsHostCh(PeekCh()), ""); 00121 do { 00122 while (ChDef.IsHostCh(PeekCh())){Str+=GetCh();} 00123 if (PeekCh()=='.'){Str+=GetCh('.');} 00124 else if (PeekCh()=='@'){GetCh('@'); Str.Clr();} // still unexplained 00125 } while (ChDef.IsHostCh(PeekCh())); 00126 Str.ToLc(); 00127 return Str; 00128 } 00129 00130 TStr TUrlLx::GetHostPort(TStr& HostNm, TStr& PortStr, int& PortN){TChA Str; 00131 Str+=HostNm=GetHost(); 00132 if (PeekCh()==':'){ 00133 Str+=GetCh(':'); 00134 if (IsDigitCh()){Str+=PortStr=GetDigits(); PortN=PortStr.GetInt();} 00135 } 00136 return Str; 00137 } 00138 00139 TStr TUrlLx::GetHPath(TStrV& PathSegV){TChA Str; TChA HSegStr; bool Cont; 00140 do { 00141 while (PeekCh()=='/'){GetCh('/');} // prevent multiple '/' 00142 HSegStr.Clr(); while (IsHSegmentCh()){HSegStr+=GetHSegmentCh();} 00143 Str+=HSegStr; PathSegV.Add(HSegStr); 00144 Cont=(PeekCh()=='/'); if (Cont){Str+=GetCh('/');} 00145 } while (Cont); 00146 return Str; 00147 } 00148 00150 // Url 00151 const TStr TUrl::UrlHttpPrefixStr="http:"; 00152 const TStr TUrl::UrlHttpAbsPrefixStr="http://"; 00153 00154 void TUrl::GetAbs(const TStr& AbsUrlStr){ 00155 EAssertR(IsAbs(AbsUrlStr), AbsUrlStr); 00156 TUrlLx Lx(AbsUrlStr); TChA Str; 00157 Str+=SchemeNm=Lx.GetScheme(); Str+=Lx.GetCh(':'); 00158 if (SchemeNm=="http"){ 00159 Scheme=usHttp; 00160 const char *DbSlashStr="//"; 00161 Str+=Lx.GetStr(DbSlashStr); 00162 Str+=Lx.GetHostPort(HostNm, PortStr, PortN); 00163 if (PortN==-1){PortN=THttp::DfPortN; PortStr.Clr();} 00164 else if (PortN==THttp::DfPortN){PortStr.Clr();} 00165 //**if (!PortStr.Empty()){Str+=':'; Str+=PortStr;} 00166 if (Lx.PeekCh()=='/'){ 00167 PathStr=Lx.GetCh('/'); PathStr+=Lx.GetHPath(PathSegV); Str+=PathStr;} 00168 if (PathStr.Empty()){PathStr="/"; Str+=PathStr;} 00169 if (Lx.PeekCh()=='?'){ 00170 SearchStr=Lx.GetCh('?'); SearchStr+=Lx.GetSearch(); Str+=SearchStr;} 00171 } else { 00172 Scheme=usOther; Str+=Lx.GetToCh(); 00173 } 00174 while (Lx.PeekCh()==' '){Lx.GetCh();} 00175 if (Lx.PeekCh()=='#'){ 00176 FragIdStr=Lx.GetCh('#'); FragIdStr+=Lx.GetToCh(); 00177 } 00178 EAssertR(Lx.Eof(), ""); 00179 UrlStr=Str; 00180 } 00181 00182 void TUrl::GetAbsFromBase(const TStr& RelUrlStr, const TStr& BaseUrlStr){ 00183 EAssertR(!BaseUrlStr.Empty(), ""); 00184 PUrl Url=TUrl::New(BaseUrlStr); EAssertR(Url->IsOk(), ""); 00185 EAssertR(IsAbs(BaseUrlStr), ""); 00186 TStr AbsUrlStr=BaseUrlStr; 00187 TStr NrRelUrlStr=RelUrlStr; 00188 if (NrRelUrlStr.GetLc().IsPrefix(UrlHttpPrefixStr)){ 00189 NrRelUrlStr.DelSubStr(0, UrlHttpPrefixStr.Len()-1);} 00190 if (NrRelUrlStr.Len()>0){ 00191 if (NrRelUrlStr[0]=='/'){ 00192 TStr SlashStr; int SlashChN=0; 00193 while ((SlashChN<NrRelUrlStr.Len())&&(NrRelUrlStr[SlashChN]=='/')){ 00194 SlashChN++; SlashStr+="/";} 00195 int ChN=0; bool Found=false; 00196 while ((!Found)&&((ChN=AbsUrlStr.SearchStr(SlashStr, ChN))!=-1)){ 00197 TStr Str=AbsUrlStr.GetSubStr(ChN-1, ChN+SlashStr.Len()-1+1); 00198 Found=((ChN==0)||(Str[0]!='/'))&& 00199 ((ChN+SlashStr.Len()-1==AbsUrlStr.Len()-1)||(Str[Str.Len()-1]!='/')); 00200 if (!Found){ChN++;} 00201 } 00202 if (Found){ 00203 AbsUrlStr.DelSubStr(ChN, AbsUrlStr.Len()-1); 00204 AbsUrlStr+=NrRelUrlStr; 00205 } 00206 } else { 00207 int ChN=AbsUrlStr.Len()-1; 00208 while ((ChN>=0)&&(AbsUrlStr[ChN]!='/')){ChN--;} 00209 AbsUrlStr.DelSubStr(ChN+1, AbsUrlStr.Len()-1); 00210 AbsUrlStr+=NrRelUrlStr; 00211 } 00212 } 00213 00214 const char *PrevDirStr="/../"; 00215 {int ChN; 00216 while ((ChN=AbsUrlStr.SearchStr(PrevDirStr))!=-1){ 00217 int BChN=ChN; int EChN=ChN+(int) strlen(PrevDirStr)-1; 00218 while ((BChN-1>=0)&&(AbsUrlStr[BChN-1]!='/')){BChN--;} 00219 AbsUrlStr.DelSubStr(BChN, EChN); 00220 }} 00221 00222 const char *CurDirStr="/."; 00223 while (AbsUrlStr.DelStr(CurDirStr)){} 00224 00225 GetAbs(AbsUrlStr); 00226 } 00227 00228 TUrl::TUrl(const TStr& _RelUrlStr, const TStr& _BaseUrlStr): 00229 Scheme(usUndef), 00230 UrlStr(), RelUrlStr(_RelUrlStr), BaseUrlStr(_BaseUrlStr), 00231 SchemeNm(), HostNm(), 00232 PortStr(), PathStr(), SearchStr(), FragIdStr(), 00233 PortN(-1), PathSegV(), 00234 IpNum(), 00235 FinalUrlStr(), FinalHostNm(), 00236 HttpRqStr(){ 00237 RelUrlStr.ToTrunc(); 00238 RelUrlStr.ChangeStrAll(" ", "%20"); 00239 try { 00240 if (IsAbs(RelUrlStr)){ 00241 GetAbs(RelUrlStr); 00242 } else 00243 if (IsAbs(BaseUrlStr)){ 00244 GetAbsFromBase(RelUrlStr, BaseUrlStr); 00245 } else { 00246 Scheme=usUndef; 00247 } 00248 } 00249 catch (PExcept&){Scheme=usUndef;} 00250 00251 //** old version 00252 /* 00253 PUrl BaseUrl; 00254 if (!BaseUrlStr.Empty()){ // must be outside try-block (CBuilder3.0 bug) 00255 BaseUrl=TUrl::New(BaseUrlStr);} 00256 try { 00257 if (!BaseUrlStr.Empty()){ 00258 EAssertR(BaseUrl->IsOk(), "");} 00259 if (IsAbs(RelUrlStr)){ 00260 GetAbs(RelUrlStr); 00261 } else { 00262 GetAbsFromBase(RelUrlStr, BaseUrlStr); 00263 } 00264 } 00265 catch (PExcept&){Scheme=usUndef;} 00266 */ 00267 } 00268 00269 TStr TUrl::GetDmNm(const int& MxDmSegs) const { 00270 EAssert(IsOk()); 00271 TChA DmChA; int DmSegs=0; 00272 for (int ChN=HostNm.Len()-1; ChN>=0; ChN--){ 00273 if (HostNm[ChN]=='.'){ 00274 DmSegs++; 00275 if (DmSegs==MxDmSegs){break;} else {DmChA+='.';} 00276 } else { 00277 DmChA+=HostNm[ChN]; 00278 } 00279 } 00280 DmChA.Reverse(); 00281 return DmChA; 00282 } 00283 00284 void TUrl::DefFinalUrl(const TStr& _FinalHostNm){ 00285 EAssert(IsOk(usHttp)); 00286 EAssert(!IsDefFinalUrl()); 00287 FinalHostNm=_FinalHostNm.GetLc(); 00288 if (HostNm==FinalHostNm){ 00289 FinalUrlStr=UrlStr; 00290 } else { 00291 TChA FinalUrlChA; 00292 FinalUrlChA+=SchemeNm; FinalUrlChA+="://"; 00293 FinalUrlChA+=FinalHostNm; 00294 if (!PortStr.Empty()){ 00295 FinalUrlChA+=":"; FinalUrlChA+=PortStr;} 00296 FinalUrlChA+=PathStr; 00297 FinalUrlChA+=SearchStr; 00298 FinalUrlStr=FinalUrlChA; 00299 } 00300 } 00301 00302 void TUrl::ToLcPath(){ 00303 // test if the conversion is needed 00304 if (!PathStr.IsLc()){ 00305 // convert path strings to lower-case 00306 PathStr.ToLc(); 00307 for (int PathSegN=0; PathSegN<PathSegV.Len(); PathSegN++){ 00308 PathSegV[PathSegN].ToLc();} 00309 // recompose url 00310 TChA UrlChA; 00311 UrlChA+=SchemeNm; UrlChA+="://"; 00312 UrlChA+=HostNm; 00313 if (!PortStr.Empty()){ 00314 UrlChA+=":"; UrlChA+=PortStr;} 00315 UrlChA+=PathStr; 00316 UrlChA+=SearchStr; 00317 UrlStr=UrlChA; 00318 // recompose final-url 00319 if (IsDefFinalUrl()){ 00320 FinalUrlStr.Clr(); DefFinalUrl(FinalHostNm);} 00321 } 00322 } 00323 00324 bool TUrl::IsAbs(const TStr& UrlStr){ 00325 if (UrlStr.GetLc().IsPrefix(UrlHttpPrefixStr)){ 00326 return UrlStr.GetLc().IsPrefix(UrlHttpAbsPrefixStr); 00327 } else { 00328 int ColonChN=UrlStr.SearchCh(':'); int SlashChN=UrlStr.SearchCh('/'); 00329 return (ColonChN!=-1)&&((SlashChN==-1)||((SlashChN!=-1)&&(ColonChN<SlashChN))); 00330 } 00331 } 00332 00333 bool TUrl::IsScript(const TStr& UrlStr){ 00334 return UrlStr.IsChIn('?'); 00335 } 00336 00337 bool TUrl::IsSite(const TStr& UrlStr){ 00338 PUrl Url=TUrl::New(UrlStr); 00339 return Url->IsOk(usHttp) && (Url->GetPathStr()=="/") && 00340 Url->GetSearchStr().Empty() && Url->GetFragIdStr().Empty(); 00341 } 00342 00343 PUrl TUrl::GetUrlFromShortcut(const TStr& ShortcutUrlStr, 00344 const TStr& DfHostNmPrefix, const TStr& DfHostNmSufix){ 00345 // shortcut is already correct url 00346 TStr UrlStr=ShortcutUrlStr; 00347 PUrl Url=TUrl::New(UrlStr); 00348 if (Url->IsOk()){return Url;} 00349 // add 'http://' to shortcut (if shortcut is from more segments) 00350 if (ShortcutUrlStr.IsChIn('.')){ 00351 UrlStr=TUrl::UrlHttpAbsPrefixStr+ShortcutUrlStr; 00352 Url=TUrl::New(UrlStr); 00353 if (Url->IsOk()){return Url;} 00354 } 00355 // add 'http://' and '/' to shortcut (if shortcut is from more segments) 00356 if (ShortcutUrlStr.IsChIn('.')){ 00357 UrlStr=TUrl::UrlHttpAbsPrefixStr+ShortcutUrlStr+"/"; 00358 Url=TUrl::New(UrlStr); 00359 if (Url->IsOk()){return Url;} 00360 } 00361 // add 'http://', prefix, postfix and '/' to shortcut 00362 UrlStr=UrlHttpAbsPrefixStr+ 00363 DfHostNmPrefix+"."+ShortcutUrlStr+"."+DfHostNmSufix+"/"; 00364 Url=TUrl::New(UrlStr); 00365 return Url; 00366 } 00367 00368 TStr TUrl::GetUrlSearchStr(const TStr& Str){ 00369 TChA InChA=Str; TChA OutChA; 00370 for (int ChN=0; ChN<InChA.Len(); ChN++){ 00371 char Ch=InChA[ChN]; 00372 if (Ch==' '){ 00373 OutChA+='+'; 00374 } else 00375 if ((' '<Ch)&&(Ch<='~')&&(Ch!='+')&&(Ch!='&')&&(Ch!='%')){ 00376 OutChA+=Ch; 00377 } else { 00378 OutChA+='%'; 00379 OutChA+=TInt::GetHexStr(uchar(Ch)/16); 00380 OutChA+=TInt::GetHexStr(uchar(Ch)%16); 00381 } 00382 } 00383 return OutChA; 00384 } 00385 00386 TStr TUrl::DecodeUrlStr(const TStr& UrlStr) { 00387 TChA InChA=UrlStr; TChA OutChA; 00388 for (int ChN=0; ChN<InChA.Len(); ChN++){ 00389 char Ch=InChA[ChN]; 00390 if (Ch=='+'){ 00391 OutChA+=' '; 00392 } else if (Ch=='%') { 00393 ChN++; if (ChN==InChA.Len()) { break; } 00394 char FirstCh = InChA[ChN]; 00395 if (!TCh::IsHex(FirstCh)) { break; } 00396 ChN++; if (ChN==InChA.Len()) { break; } 00397 char SecondCh = InChA[ChN]; 00398 if (!TCh::IsHex(SecondCh)) { break; } 00399 OutChA+=char(TCh::GetHex(FirstCh)*16 + TCh::GetHex(SecondCh)); 00400 } else { 00401 OutChA+=Ch; 00402 } 00403 } 00404 return OutChA; 00405 } 00406 00407 TStr TUrl::GetDocStrFromUrlStr(const TStr& UrlStr, const int& Copies){ 00408 TStrV StrV; UrlStr.SplitOnNonAlNum(StrV); 00409 TChA DocChA; 00410 for (int StrN=0; StrN<StrV.Len(); StrN++){ 00411 TStr UcStr=StrV[StrN].GetUc(); 00412 if ((UcStr.Len()>3)&&(UcStr!="HTTP")&&(UcStr!="HTML")&&(UcStr!="INDEX")&&(UcStr!="DEFAULT")){ 00413 for (int CopyN=0; CopyN<Copies; CopyN++){ 00414 if (!DocChA.Empty()){DocChA+=' ';} DocChA+=StrV[StrN]; 00415 } 00416 } 00417 } 00418 return DocChA; 00419 } 00420 00421 TStr TUrl::GetTopDownDocNm( 00422 const TStr& UrlStr, const int& MxLen, const bool& HostOnlyP){ 00423 PUrl Url=TUrl::New(UrlStr); 00424 TChA DocNm; 00425 if (Url->IsOk()){ 00426 TStr HostNm=Url->GetHostNm().GetLc(); 00427 TStrV HostNmSegV; HostNm.SplitOnAllCh('.', HostNmSegV, false); 00428 for (int HostNmSegN=0; HostNmSegN<HostNmSegV.Len(); HostNmSegN++){ 00429 if (HostNmSegN>0){DocNm+='.';} 00430 DocNm+=HostNmSegV[HostNmSegV.Len()-HostNmSegN-1]; 00431 } 00432 if (!HostOnlyP){ 00433 DocNm+=Url->GetPathStr().GetLc(); 00434 } 00435 } else { 00436 DocNm=UrlStr.GetLc(); 00437 } 00438 if (MxLen!=-1){ 00439 DocNm.Trunc(MxLen);} 00440 return DocNm; 00441 } 00442 00444 // Url-Search-Environment 00445 TStr TUrlEnv::GetFullUrlStr() const { 00446 if (GetKeys()==0){return TStr();} 00447 TChA SearchChA; 00448 SearchChA+=BaseUrlStr; 00449 SearchChA+="?"; 00450 int KeyVals=0; 00451 for (int KeyN=0; KeyN<GetKeys(); KeyN++){ 00452 TStr KeyNm=GetKeyNm(KeyN); 00453 TStrV ValStrV=KeyNmToValH.GetDat(KeyNm); 00454 for (int ValStrN=0; ValStrN<ValStrV.Len(); ValStrN++){ 00455 if (KeyVals>0){SearchChA+="&";} 00456 SearchChA+=TUrl::GetUrlSearchStr(KeyNm); 00457 SearchChA+='='; 00458 SearchChA+=TUrl::GetUrlSearchStr(ValStrV[ValStrN]); 00459 KeyVals++; 00460 } 00461 } 00462 return SearchChA; 00463 } 00464 00465 PUrlEnv TUrlEnv::MkClone(const PUrlEnv& UrlEnv){ 00466 PUrlEnv CloneUrlEnv= 00467 PUrlEnv(new TUrlEnv(*UrlEnv)); 00468 return CloneUrlEnv; 00469 } 00470