当前位置: 首页>>代码示例>>C++>>正文


C++ FHttpResponsePtr::IsValid方法代码示例

本文整理汇总了C++中FHttpResponsePtr::IsValid方法的典型用法代码示例。如果您正苦于以下问题:C++ FHttpResponsePtr::IsValid方法的具体用法?C++ FHttpResponsePtr::IsValid怎么用?C++ FHttpResponsePtr::IsValid使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在FHttpResponsePtr的用法示例。


在下文中一共展示了FHttpResponsePtr::IsValid方法的9个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。

示例1: HandleFileRequest

void UBPDownloader::HandleFileRequest(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
	RemoveFromRoot();

	if (bSucceeded && HttpResponse.IsValid() && HttpResponse->GetContentLength() > 0)
	{

		TArray<uint8> data = HttpResponse->GetContent();

		if (!FFileHelper::SaveArrayToFile(data, *FilePath))
		{
			OnFail.Broadcast(0.f);
			UE_LOG(LogTemp, Warning, TEXT("Unable to save file!"));
		}
		else
		{
			OnProgressUpdate.Broadcast(1.f);
			UE_LOG(LogTemp, Warning, TEXT("File download completed!"));
		}

	}

	OnFail.Broadcast(0.f);//FilePath	
}
开发者ID:MatrIsCool,项目名称:UE4Downloader,代码行数:24,代码来源:BPDownloader.cpp

示例2: MeUser_HttpRequestComplete

void FOnlineIdentityLeet::MeUser_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
	UE_LOG_ONLINE(Display, TEXT("FOnlineIdentityLeet::MeUser_HttpRequestComplete"));
	bool bResult = false;
	FString ResponseStr, ErrorStr;
	FUserOnlineAccountLeet User;

	FPendingLoginUser PendingRegisterUser = LoginUserRequests.FindRef(HttpRequest.Get());
	// Remove the request from list of pending entries
	LoginUserRequests.Remove(HttpRequest.Get());

	if (bSucceeded &&
		HttpResponse.IsValid())
	{
		ResponseStr = HttpResponse->GetContentAsString();
		if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
		{
			UE_LOG(LogOnline, Verbose, TEXT("RegisterUser request complete. url=%s code=%d response=%s"),
				*HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr);

			if (User.FromJson(ResponseStr))
			{
				if (!User.UserId.IsEmpty())
				{
					// copy and construct the unique id
					TSharedRef<FUserOnlineAccountLeet> UserRef(new FUserOnlineAccountLeet(User));
					UserRef->UserIdPtr = MakeShareable(new FUniqueNetIdString(User.UserId));
					// update/add cached entry for user
					UserAccounts.Add(User.UserId, UserRef);
					// update the access token
					UserRef->AuthTicket = PendingRegisterUser.AccessToken;
					// keep track of user ids for local users
					UserIds.Add(PendingRegisterUser.LocalUserNum, UserRef->GetUserId());

					bResult = true;
				}
				else
				{
					ErrorStr = FString::Printf(TEXT("Missing user id. payload=%s"),
						*ResponseStr);
				}
			}
			else
			{
				ErrorStr = FString::Printf(TEXT("Invalid response payload=%s"),
					*ResponseStr);
			}
		}
		else
		{
			ErrorStr = FString::Printf(TEXT("Invalid response. code=%d error=%s"),
				HttpResponse->GetResponseCode(), *ResponseStr);
		}
	}
	else
	{
		ErrorStr = TEXT("No response");
	}
	if (!ErrorStr.IsEmpty())
	{
		UE_LOG(LogOnline, Warning, TEXT("RegisterUser request failed. %s"), *ErrorStr);
	}

	TriggerOnLoginCompleteDelegates(PendingRegisterUser.LocalUserNum, bResult, FUniqueNetIdString(User.UserId), ErrorStr);
}
开发者ID:LeetCoinTeam,项目名称:LeetClient,代码行数:65,代码来源:OnlineIdentityLeet.cpp

示例3: EnumerateFiles_HttpRequestComplete

void FCdnNewsFeedTitleFile::EnumerateFiles_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
	IHttpRequest* Request;
	EnumerateFilesRequests.Dequeue(Request);

	bool bResult = false;
	FString ResponseStr, ErrorStr;

	if (bSucceeded && HttpResponse.IsValid())
	{
		ResponseStr = HttpResponse->GetContentAsString();
		if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
		{
			UE_LOG(LogEpicStorage, Verbose, TEXT("EnumerateFiles request complete. url=%s code=%d response=%s"), 
				*HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr);

			FileHeaders.Empty();

			// Make sure the response is an array
			if (!ResponseStr.StartsWith(TEXT("[")))
			{
				ResponseStr = FString(TEXT("[")) + ResponseStr + FString(TEXT("]"));
			}

			// Json parser expects arrays to always be wrapped with object
			FString ResponseStrJson = FString(TEXT("{\"files\":")) + ResponseStr + FString(TEXT("}"));
			// Create the Json parser
			TSharedPtr<FJsonObject> JsonObject;
			TSharedRef<TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(ResponseStrJson);

			if (FJsonSerializer::Deserialize(JsonReader,JsonObject) &&
				JsonObject.IsValid())
			{
				// Parse the array of file headers
				TArray<TSharedPtr<FJsonValue> > JsonFileHeaders = JsonObject->GetArrayField(TEXT("files"));
				for (TArray<TSharedPtr<FJsonValue> >::TConstIterator It(JsonFileHeaders); It; ++It)
				{
					TSharedPtr<FJsonObject> JsonFileHeader = (*It)->AsObject();
					if (JsonFileHeader.IsValid())
					{
						FCloudFileHeader FileHeader;
						if (JsonFileHeader->HasField(TEXT("hash")))
						{
							FileHeader.Hash = JsonFileHeader->GetStringField(TEXT("hash"));
						}
						if (JsonFileHeader->HasField(TEXT("uniqueFilename")))
						{
							FileHeader.DLName = JsonFileHeader->GetStringField(TEXT("uniqueFilename"));
						}
						if (JsonFileHeader->HasField(TEXT("filename")))
						{
							FileHeader.FileName = JsonFileHeader->GetStringField(TEXT("filename"));
						}
						if (JsonFileHeader->HasField(TEXT("length")))
						{
							FileHeader.FileSize = FMath::TruncToInt(JsonFileHeader->GetNumberField(TEXT("length")));
						}

						if (FileHeader.FileName.IsEmpty())
						{
							FileHeader.FileName = FileHeader.DLName;
						}

						if (FileHeader.Hash.IsEmpty() ||
							FileHeader.DLName.IsEmpty())
						{
							UE_LOG(LogEpicStorage, Warning, TEXT("Invalid file entry hash=%s dlname=%s filename=%s"),
								*FileHeader.Hash, *FileHeader.DLName, *FileHeader.FileName);
						}
						else
						{
							FileHeaders.Add(FileHeader);
						}
					}
				}
				bResult = true;
			}	
			else
			{
				ErrorStr = FString::Printf(TEXT("Invalid response payload=%s"),
					*ResponseStr);
			}
			
		}
		else
		{
			ErrorStr = FString::Printf(TEXT("Invalid response. code=%d error=%s"),
				HttpResponse->GetResponseCode(), *ResponseStr);
		}
	}


	if (!ErrorStr.IsEmpty())
	{
		UE_LOG(LogEpicStorage, Warning, TEXT("EnumerateFiles request failed. %s"), *ErrorStr);
	}

	TriggerOnEnumerateFilesCompleteDelegates(bResult);
}
开发者ID:Codermay,项目名称:Unreal4,代码行数:99,代码来源:CdnNewsFeedTitleFile.cpp

示例4: ReadFile_HttpRequestComplete

void FCdnNewsFeedTitleFile::ReadFile_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
	if (!HttpRequest.IsValid())
	{
		return;
	}

	const FPendingFileRequest* PendingRequest = FileRequests.Find(HttpRequest.Get());

	if (PendingRequest == nullptr)
	{
		return;
	}

	bool bResult = false;
	FString ResponseStr, ErrorStr;

	// Cloud file being operated on
	{
		FCloudFile* CloudFile = GetCloudFile(PendingRequest->FileName, true);
		CloudFile->AsyncState = EOnlineAsyncTaskState::Failed;
		CloudFile->Data.Empty();
	}
	
	if (bSucceeded && 
		HttpResponse.IsValid())
	{
		
		if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
		{
			UE_LOG(LogEpicStorage, Verbose, TEXT("ReadFile request complete. url=%s code=%d"), 
				*HttpRequest->GetURL(), HttpResponse->GetResponseCode());

			// update the memory copy of the file with data that was just downloaded
			FCloudFile* CloudFile = GetCloudFile(PendingRequest->FileName, true);
			CloudFile->AsyncState = EOnlineAsyncTaskState::Done;
			CloudFile->Data = HttpResponse->GetContent();

			// cache to disk on successful download
			SaveCloudFileToDisk(CloudFile->FileName,CloudFile->Data);

			bResult = true;
		}
		else
		{
			ErrorStr = FString::Printf(TEXT("Invalid response. code=%d error=%s"),
				HttpResponse->GetResponseCode(), *HttpResponse->GetContentAsString());
		}
	}
	else
	{
		ErrorStr = TEXT("No response");
	}

	if (!ErrorStr.IsEmpty())
	{
		UE_LOG(LogEpicStorage, Warning, TEXT("ReadFile request failed. %s"), *ErrorStr);
	}

	TriggerOnReadFileCompleteDelegates(bResult, PendingRequest->FileName);

	FileRequests.Remove(HttpRequest.Get());
}
开发者ID:Codermay,项目名称:Unreal4,代码行数:63,代码来源:CdnNewsFeedTitleFile.cpp

示例5: Query_HttpRequestComplete

void SSuperSearchBox::Query_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
	bool bResult = false;
	FString ResponseStr, ErrorStr;

	if (bSucceeded && HttpResponse.IsValid())
	{
		ResponseStr = HttpResponse->GetContentAsString();
		if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
		{
			// Create the Json parser
			TSharedPtr<FJsonObject> JsonObject;
			TSharedRef<TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(ResponseStr);

			if (FJsonSerializer::Deserialize(JsonReader, JsonObject) && JsonObject.IsValid())
			{
				if (FText * QueryText = RequestQueryMap.Find(HttpRequest))
				{
					const TArray<TSharedPtr<FJsonValue> > * JsonItems = nullptr;
					if (JsonObject->TryGetArrayField(TEXT("items"), JsonItems))
					{
						//add search result into cache
						FSearchResults & SearchResults = SearchResultsCache.FindOrAdd(QueryText->ToString());
						FCategoryResults & OnlineResults = SearchResults.OnlineResults;
						OnlineResults.Empty();	//reset online results since we just got updated

						for (TSharedPtr<FJsonValue> JsonItem : *JsonItems)
						{
							const TSharedPtr<FJsonObject> & ItemObject = JsonItem->AsObject();
							FSearchEntry SearchEntry;
							SearchEntry.Title = ItemObject->GetStringField("title");
							SearchEntry.URL = ItemObject->GetStringField("link");
							SearchEntry.bCategory = false;

							bool bValidLabel = false;
							TArray<TSharedPtr<FJsonValue> > Labels = ItemObject->GetArrayField(TEXT("labels"));
							for (TSharedPtr<FJsonValue> Label : Labels)
							{
								const TSharedPtr<FJsonObject> & LabelObject = Label->AsObject();
								FString LabelString = LabelObject->GetStringField(TEXT("name"));
								TArray<FSearchEntry> & SuggestionCategory = OnlineResults.FindOrAdd(LabelString);
								SuggestionCategory.Add(SearchEntry);
							}
						}
					}

					bResult = true;
				}
				
			}
		}
		else
		{
			ErrorStr = FString::Printf(TEXT("Invalid response. code=%d error=%s"),
				HttpResponse->GetResponseCode(), *ResponseStr);
		}
	}

	if (bResult)
	{
		UpdateSuggestions();
	}
}
开发者ID:frobro98,项目名称:UnrealSource,代码行数:63,代码来源:SSuperSearch.cpp

示例6: QueryFriendsList_HttpRequestComplete

void FOnlineFriendsFacebook::QueryFriendsList_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded, FOnReadFriendsListComplete Delegate)
{
	bool bResult = false;
	FString ResponseStr, ErrorStr;

	FPendingFriendsQuery PendingFriendsQuery = FriendsQueryRequests.FindRef(HttpRequest.Get());
	// Remove the request from list of pending entries
	FriendsQueryRequests.Remove(HttpRequest.Get());

	if (bSucceeded &&
		HttpResponse.IsValid())
	{
		ResponseStr = HttpResponse->GetContentAsString();
		if (EHttpResponseCodes::IsOk(HttpResponse->GetResponseCode()))
		{
			UE_LOG(LogOnline, Verbose, TEXT("Query friends request complete. url=%s code=%d response=%s"), 
				*HttpRequest->GetURL(), HttpResponse->GetResponseCode(), *ResponseStr);

			// Create the Json parser
			TSharedPtr<FJsonObject> JsonObject;
			TSharedRef<TJsonReader<> > JsonReader = TJsonReaderFactory<>::Create(ResponseStr);

			if (FJsonSerializer::Deserialize(JsonReader,JsonObject) &&
				JsonObject.IsValid())
			{
				// Update cached entry for local user
				FOnlineFriendsList& FriendsList = FriendsMap.FindOrAdd(PendingFriendsQuery.LocalUserNum);
				FriendsList.Friends.Empty();

				// Should have an array of id mappings
				TArray<TSharedPtr<FJsonValue> > JsonFriends = JsonObject->GetArrayField(TEXT("data"));
				for (TArray<TSharedPtr<FJsonValue> >::TConstIterator FriendIt(JsonFriends); FriendIt; ++FriendIt)
				{
					FString UserIdStr;
					TMap<FString,FString> Attributes;
					TSharedPtr<FJsonObject> JsonFriendEntry = (*FriendIt)->AsObject();
					for (TMap<FString, TSharedPtr<FJsonValue > >::TConstIterator It(JsonFriendEntry->Values); It; ++It)
					{
						// parse user attributes
						if (It->Value.IsValid() && 
							It->Value->Type == EJson::String)
						{
							FString ValueStr = It->Value->AsString();
							if (It->Key == TEXT("id"))
							{
								UserIdStr = ValueStr;
							}
							Attributes.Add(It->Key, ValueStr);
						}
					}
					// only add if valid id
					if (!UserIdStr.IsEmpty())
					{
						TSharedRef<FOnlineFriendFacebook> FriendEntry(new FOnlineFriendFacebook(UserIdStr));
						FriendEntry->AccountData = Attributes;
						// Add new friend entry to list
						FriendsList.Friends.Add(FriendEntry);
					}
				}
				bResult = true;
			}
		}
		else
		{
			ErrorStr = FString::Printf(TEXT("Invalid response. code=%d error=%s"),
				HttpResponse->GetResponseCode(), *ResponseStr);
		}
	}
	else
	{
		ErrorStr = TEXT("No response");
	}
	if (!ErrorStr.IsEmpty())
	{
		UE_LOG(LogOnline, Warning, TEXT("Query friends list request failed. %s"), *ErrorStr);
	}

	Delegate.ExecuteIfBound(PendingFriendsQuery.LocalUserNum, bResult, EFriendsLists::ToString(EFriendsLists::Default), ErrorStr);
}
开发者ID:johndpope,项目名称:UE4,代码行数:79,代码来源:OnlineFriendsFacebook.cpp

示例7: OnProcessRequestComplete

void USIOJRequestJSON::OnProcessRequestComplete(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	// Be sure that we have no data from previous response
	ResetResponseData();

	// Check we have a response and save response code as int32
	if(Response.IsValid())
	{
		ResponseCode = Response->GetResponseCode();
	}

	// Check we have result to process futher
	if (!bWasSuccessful || !Response.IsValid())
	{
		UE_LOG(LogSIOJ, Error, TEXT("Request failed (%d): %s"), ResponseCode, *Request->GetURL());

		// Broadcast the result event
		OnRequestFail.Broadcast(this);
		OnStaticRequestFail.Broadcast(this);

		return;
	}

	// Save response data as a string
	ResponseContent = Response->GetContentAsString();

	// Log response state
	UE_LOG(LogSIOJ, Log, TEXT("Response (%d): %s"), ResponseCode, *ResponseContent);

	// Process response headers
	TArray<FString> Headers = Response->GetAllHeaders();
	for (FString Header : Headers)
	{
		FString Key;
		FString Value;
		if (Header.Split(TEXT(": "), &Key, &Value))
		{
			ResponseHeaders.Add(Key, Value);
		}
	}

	// Try to deserialize data to JSON
	TSharedRef<TJsonReader<TCHAR>> JsonReader = TJsonReaderFactory<TCHAR>::Create(ResponseContent);
	FJsonSerializer::Deserialize(JsonReader, ResponseJsonObj->GetRootObject());

	// Decide whether the request was successful
	bIsValidJsonResponse = bWasSuccessful && ResponseJsonObj->GetRootObject().IsValid();

	// Log errors
	if (!bIsValidJsonResponse)
	{
		if (!ResponseJsonObj->GetRootObject().IsValid())
		{
			// As we assume it's recommended way to use current class, but not the only one,
			// it will be the warning instead of error
			UE_LOG(LogSIOJ, Warning, TEXT("JSON could not be decoded!"));
		}
	}

	// Broadcast the result event
	OnRequestComplete.Broadcast(this);
	OnStaticRequestComplete.Broadcast(this);

	// Finish the latent action
	if (ContinueAction)
	{
          FSIOJLatentAction<USIOJsonObject*> *K = ContinueAction;
          ContinueAction = nullptr;

          K->Call(ResponseJsonObj);
	}
}
开发者ID:Melargus,项目名称:socketio-client-ue4,代码行数:72,代码来源:SIOJRequestJSON.cpp

示例8: HttpRequestComplete

		void HttpRequestComplete(	FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
		{
			if (HttpResponse.IsValid())
				Out.Append(HttpResponse->GetContent());
		}
开发者ID:RandomDeveloperM,项目名称:UE4_Hairworks,代码行数:5,代码来源:HTTPTransport.cpp

示例9: Query_HttpRequestComplete

void FOneSkyTranslationExportWorker::Query_HttpRequestComplete(FHttpRequestPtr HttpRequest, FHttpResponsePtr HttpResponse, bool bSucceeded)
{
	bool bResult = false;

	if (bSucceeded)
	{
		FString ResponseStr = HttpResponse->GetContentAsString();
		FText ErrorText;

		if (HttpResponse.IsValid())
		{
			EHttpResponseCodes::Type ResponseCode = (EHttpResponseCodes::Type) HttpResponse->GetResponseCode();

			if (EHttpResponseCodes::IsOk(ResponseCode))
			{
				// TODO: Test Accepted case.  Haven't been able to make this happen yet...
				if (ResponseCode == EHttpResponseCodes::Accepted)
				{
					if (Command != nullptr)
					{
						TSharedPtr<FDownloadLocalizationTargetFile, ESPMode::ThreadSafe> TranslationExportOp = StaticCastSharedRef<FDownloadLocalizationTargetFile>(Command->Operation);
						if (TranslationExportOp.IsValid())
						{
							// The file is not ready, try again
							TSharedRef<FDownloadLocalizationTargetFile, ESPMode::ThreadSafe> NewTranslationExportLanguagesOp = ILocalizationServiceOperation::Create<FDownloadLocalizationTargetFile>();
							NewTranslationExportLanguagesOp->SetInTargetGuid(TranslationExportOp->GetInTargetGuid());
							NewTranslationExportLanguagesOp->SetInLocale(TranslationExportOp->GetInLocale());
							NewTranslationExportLanguagesOp->SetInRelativeOutputFilePathAndName(TranslationExportOp->GetInRelativeOutputFilePathAndName());
							// TODO: Can't spawn a new Worker here, as it tries to access the OneSky Connection Info from a thread that is not the main thread.
							// Instead spawn in callback?
							//ILocalizationServiceModule::Get().GetProvider().Execute(NewTranslationExportLanguagesOp, TArray<FLocalizationServiceTranslationIdentifier>(), ELocalizationServiceOperationConcurrency::Asynchronous);
							// For now, error
							ErrorText = LOCTEXT("TranslationExportQueryFailedRetryNotImplemented", "Translation Export Query Failed: Retry not yet implemented.");
							bResult = false;
						}
						else
						{
							ErrorText = LOCTEXT("TranslationExportQueryFailedTranslationExportOpInvalid", "Translation Export Query Failed: Translation Export Operation is invalid.");
						}

						return;
					}
					else
					{
						ErrorText = LOCTEXT("TranslationExportQueryFailedCommandNull", "Translation Export Query Failed: Command is null.");
					}
				}
				else if (ResponseCode == EHttpResponseCodes::NoContent)
				{
					bResult = false;
				}
				// If there's no response code, then this is the file
				else
				{
					if (Command != nullptr)
					{
						TSharedPtr<FDownloadLocalizationTargetFile, ESPMode::ThreadSafe> TranslationExportOp = StaticCastSharedRef<FDownloadLocalizationTargetFile>(Command->Operation);
						if (TranslationExportOp.IsValid())
						{
							// Path is relative to game directory
							FString Filename = FPaths::ConvertRelativePathToFull(FPaths::GameDir() / TranslationExportOp->GetInRelativeOutputFilePathAndName());

							if (Filename.IsEmpty())
							{
								ErrorText = LOCTEXT("InvalidExportFilename", "Export filename is invalid");
								bResult = false;
							}
							else if (FFileHelper::SaveStringToFile(ResponseStr, *Filename, FFileHelper::EEncodingOptions::ForceUnicode))
							{
								bResult = true;
							}
							else
							{
								ErrorText = LOCTEXT("FailedToWriteFile", "Could not write file.");
								bResult = false;
							}
						}
						else
						{
							ErrorText = LOCTEXT("ExportFilenameNotFound", "Could not find export file name.");
							bResult = false;
						}
					}
				}
			}
			else
			{
				ErrorText = FText::Format(LOCTEXT("InvalidResponse", "Invalid response. code={0} error={1}"), FText::FromString(FString::FromInt(HttpResponse->GetResponseCode())), FText::FromString(ResponseStr));
			}
		}

		if (!bResult)
		{
			UE_LOG(LogLocalizationService, Warning, TEXT("%s"), *(ErrorText.ToString()));
			if (Command != nullptr)
			{
				Command->ErrorMessages.Add(ErrorText);
				TSharedPtr<FDownloadLocalizationTargetFile, ESPMode::ThreadSafe> DownloadLocTargetOp = StaticCastSharedRef<FDownloadLocalizationTargetFile>(Command->Operation);
				if (DownloadLocTargetOp.IsValid())
				{
//.........这里部分代码省略.........
开发者ID:aovi,项目名称:UnrealEngine4,代码行数:101,代码来源:OneSkyLocalizationServiceOperations.cpp


注:本文中的FHttpResponsePtr::IsValid方法示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。