Browse Source

#IQRV #comment [ResourceWatcher] 安装状态和安装请求实现

gifur 4 years ago
parent
commit
2b863585d1

+ 29 - 0
Module/mod_ResourceWatcher/ResourceWatcher.xml

@@ -185,6 +185,35 @@
         <param name="gateways" type="array_string"/>
         <param name="dns" type="array_string"/>
       </res>
+    </twoway>
+    <twoway  name="GetThirdPartyInstallState" overlap="true">
+      <req>
+        <!---1: 搜狗输入法-->
+        <param name="mode" type="int" />
+      </req>
+      <res>
+        <!--1:已安装-->
+        <param name="status" type="int" />
+        <param name="version" type="string"/>
+        <param name="path" type="string"/>
+        <param name="reserverd1" type="string"/>
+        <param name="reserverd2" type="string"/>
+        <param name="reserverd3" type="int"/>
+        <param name="reserverd4" type="int"/>
+      </res>
+    </twoway>
+    <twoway  name="InstallThirdPartyProgram" overlap="true">
+      <req>
+        <!---1: 搜狗输入法-->
+        <param name="type" type="int" />
+      </req>
+      <res>
+        <param name="result" type="int" />
+        <param name="msg" type="string"/>
+        <param name="path" type="string"/>
+        <param name="reserverd1" type="string"/>
+        <param name="reserverd2" type="string"/>
+      </res>
     </twoway>
 	</class>
 	<message name="QueryCardSwiper">

+ 58 - 0
Module/mod_ResourceWatcher/ResourceWatcher_client_g.h

@@ -271,6 +271,64 @@ public:
 		return Error;
 	}
 
+	ErrorCodeEnum GetThirdPartyInstallState(ResourceWatcherService_GetThirdPartyInstallState_Req &Req, CSmartPointer<IAsynWaitSp> &spAsyncWait, DWORD dwTimeout)
+	{
+		CSmartPointer<IClientSessionFunction> pFunc = GetFunction();
+		CAutoBuffer Buf = SpObject2Buffer(Req);
+		return pFunc->AsyncRequest(ResourceWatcherService_Method_GetThirdPartyInstallState, ResourceWatcherService_MethodSignature_GetThirdPartyInstallState, Buf, spAsyncWait, dwTimeout);
+	}
+	ErrorCodeEnum GetThirdPartyInstallState(ResourceWatcherService_GetThirdPartyInstallState_Req &Req, ResourceWatcherService_GetThirdPartyInstallState_Ans &Ans, DWORD dwTimeout)
+	{
+		CSmartPointer<IAsynWaitSp> spAsyncWait;
+		ErrorCodeEnum Error = GetThirdPartyInstallState(Req, spAsyncWait, dwTimeout);
+		if (Error == Error_Succeed) {
+			bool bEnd = false;
+			Error = SpWaitAnswerObject(spAsyncWait, Ans, bEnd, dwTimeout);
+			LOG_ASSERT(Error || bEnd);
+		}
+		return Error;
+	}
+	ErrorCodeEnum GetThirdPartyInstallState(ResourceWatcherService_GetThirdPartyInstallState_Req &Req, ResourceWatcherService_GetThirdPartyInstallState_Ans &Ans, DWORD dwTimeout, DWORD &dwUserError)
+	{
+		CSmartPointer<IAsynWaitSp> spAsyncWait;
+		ErrorCodeEnum Error = GetThirdPartyInstallState(Req, spAsyncWait, dwTimeout);
+		if (Error == Error_Succeed) {
+			bool bEnd = false;
+			Error = SpWaitAnswerObject(spAsyncWait, Ans, bEnd, dwUserError, dwTimeout);
+			LOG_ASSERT(Error || bEnd);
+		}
+		return Error;
+	}
+
+	ErrorCodeEnum InstallThirdPartyProgram(ResourceWatcherService_InstallThirdPartyProgram_Req &Req, CSmartPointer<IAsynWaitSp> &spAsyncWait, DWORD dwTimeout)
+	{
+		CSmartPointer<IClientSessionFunction> pFunc = GetFunction();
+		CAutoBuffer Buf = SpObject2Buffer(Req);
+		return pFunc->AsyncRequest(ResourceWatcherService_Method_InstallThirdPartyProgram, ResourceWatcherService_MethodSignature_InstallThirdPartyProgram, Buf, spAsyncWait, dwTimeout);
+	}
+	ErrorCodeEnum InstallThirdPartyProgram(ResourceWatcherService_InstallThirdPartyProgram_Req &Req, ResourceWatcherService_InstallThirdPartyProgram_Ans &Ans, DWORD dwTimeout)
+	{
+		CSmartPointer<IAsynWaitSp> spAsyncWait;
+		ErrorCodeEnum Error = InstallThirdPartyProgram(Req, spAsyncWait, dwTimeout);
+		if (Error == Error_Succeed) {
+			bool bEnd = false;
+			Error = SpWaitAnswerObject(spAsyncWait, Ans, bEnd, dwTimeout);
+			LOG_ASSERT(Error || bEnd);
+		}
+		return Error;
+	}
+	ErrorCodeEnum InstallThirdPartyProgram(ResourceWatcherService_InstallThirdPartyProgram_Req &Req, ResourceWatcherService_InstallThirdPartyProgram_Ans &Ans, DWORD dwTimeout, DWORD &dwUserError)
+	{
+		CSmartPointer<IAsynWaitSp> spAsyncWait;
+		ErrorCodeEnum Error = InstallThirdPartyProgram(Req, spAsyncWait, dwTimeout);
+		if (Error == Error_Succeed) {
+			bool bEnd = false;
+			Error = SpWaitAnswerObject(spAsyncWait, Ans, bEnd, dwUserError, dwTimeout);
+			LOG_ASSERT(Error || bEnd);
+		}
+		return Error;
+	}
+
 
 	bool SafeDelete()
 	{

+ 58 - 0
Module/mod_ResourceWatcher/ResourceWatcher_def_g.h

@@ -20,6 +20,8 @@ namespace ResourceWatcher {
 #define ResourceWatcherService_Method_ExtractEventLog 4
 #define ResourceWatcherService_Method_UpdateDNS 5
 #define ResourceWatcherService_Method_GetNetworkInfo 6
+#define ResourceWatcherService_Method_GetThirdPartyInstallState 7
+#define ResourceWatcherService_Method_InstallThirdPartyProgram 8
 
 #define ResourceWatcherService_MethodSignature_Fetch -1944912560
 #define ResourceWatcherService_MethodSignature_GetDevInfo 296205965
@@ -29,6 +31,8 @@ namespace ResourceWatcher {
 #define ResourceWatcherService_MethodSignature_ExtractEventLog -1046715334
 #define ResourceWatcherService_MethodSignature_UpdateDNS -943970884
 #define ResourceWatcherService_MethodSignature_GetNetworkInfo 1741482404
+#define ResourceWatcherService_MethodSignature_GetThirdPartyInstallState -15861483
+#define ResourceWatcherService_MethodSignature_InstallThirdPartyProgram -1049249852
 
 struct ResourceWatcherService_Fetch_Req
 {
@@ -257,6 +261,60 @@ struct ResourceWatcherService_GetNetworkInfo_Ans
 
 };
 
+struct ResourceWatcherService_GetThirdPartyInstallState_Req
+{
+	int mode;
+
+	void Serialize(SpBuffer &Buf)
+	{
+		auto & buf = Buf & mode;
+	}
+
+};
+
+struct ResourceWatcherService_GetThirdPartyInstallState_Ans
+{
+	int status;
+	CSimpleStringA version;
+	CSimpleStringA path;
+	CSimpleStringA reserverd1;
+	CSimpleStringA reserverd2;
+	int reserverd3;
+	int reserverd4;
+
+	void Serialize(SpBuffer &Buf)
+	{
+		auto & buf = Buf & status & version & path & reserverd1 & reserverd2 & reserverd3 & reserverd4;
+	}
+
+};
+
+struct ResourceWatcherService_InstallThirdPartyProgram_Req
+{
+	int type;
+
+	void Serialize(SpBuffer &Buf)
+	{
+		auto & buf = Buf & type;
+	}
+
+};
+
+struct ResourceWatcherService_InstallThirdPartyProgram_Ans
+{
+	int result;
+	CSimpleStringA msg;
+	CSimpleStringA path;
+	CSimpleStringA reserverd1;
+	CSimpleStringA reserverd2;
+
+	void Serialize(SpBuffer &Buf)
+	{
+		auto & buf = Buf & result & msg & path & reserverd1 & reserverd2;
+	}
+
+};
+
 
 ///////////////////////////
 

+ 50 - 0
Module/mod_ResourceWatcher/ResourceWatcher_server_g.h

@@ -86,6 +86,20 @@ public:
 				Error = Error_MethodSignatureFailed;
 			}
 			break;
+		case ResourceWatcherService_Method_GetThirdPartyInstallState:
+			if (dwSignature == ResourceWatcherService_MethodSignature_GetThirdPartyInstallState) {
+				bOverlap = true;
+			} else {
+				Error = Error_MethodSignatureFailed;
+			}
+			break;
+		case ResourceWatcherService_Method_InstallThirdPartyProgram:
+			if (dwSignature == ResourceWatcherService_MethodSignature_InstallThirdPartyProgram) {
+				bOverlap = true;
+			} else {
+				Error = Error_MethodSignatureFailed;
+			}
+			break;
 		default:
 			Error = Error_MethodNotFound;
 			break;
@@ -137,6 +151,16 @@ public:
 				Error = Error_MethodSignatureFailed;
 			}
 			break;
+		case ResourceWatcherService_Method_GetThirdPartyInstallState:
+			if (dwSignature != ResourceWatcherService_MethodSignature_GetThirdPartyInstallState) {
+				Error = Error_MethodSignatureFailed;
+			}
+			break;
+		case ResourceWatcherService_Method_InstallThirdPartyProgram:
+			if (dwSignature != ResourceWatcherService_MethodSignature_InstallThirdPartyProgram) {
+				Error = Error_MethodSignatureFailed;
+			}
+			break;
 		default:
 			Error = Error_MethodNotFound;
 			break;
@@ -184,6 +208,16 @@ public:
 	/// override by user
 	}
 
+	virtual void Handle_GetThirdPartyInstallState(SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req, ResourceWatcherService_GetThirdPartyInstallState_Ans>::Pointer ctx)
+	{
+	/// override by user
+	}
+
+	virtual void Handle_InstallThirdPartyProgram(SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req, ResourceWatcherService_InstallThirdPartyProgram_Ans>::Pointer ctx)
+	{
+	/// override by user
+	}
+
 	virtual void OnRequest(CSmartPointer<ITransactionContext> pTransactionContext)
 	{
 		CAutoBuffer Buf;
@@ -264,6 +298,22 @@ public:
 						Handle_GetNetworkInfo(ctx);
 					}
 					break;
+				case ResourceWatcherService_Method_GetThirdPartyInstallState:
+					{
+						SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req,ResourceWatcherService_GetThirdPartyInstallState_Ans>::Pointer ctx;
+						ctx.Attach(new SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req,ResourceWatcherService_GetThirdPartyInstallState_Ans>(pTransactionContext));
+						SpBuffer2Object(Buf, ctx->Req);
+						Handle_GetThirdPartyInstallState(ctx);
+					}
+					break;
+				case ResourceWatcherService_Method_InstallThirdPartyProgram:
+					{
+						SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req,ResourceWatcherService_InstallThirdPartyProgram_Ans>::Pointer ctx;
+						ctx.Attach(new SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req,ResourceWatcherService_InstallThirdPartyProgram_Ans>(pTransactionContext));
+						SpBuffer2Object(Buf, ctx->Req);
+						Handle_InstallThirdPartyProgram(ctx);
+					}
+					break;
 				default:
 					assert(0);
 					break;

+ 210 - 0
Module/mod_ResourceWatcher/mod_ResourceWatcher.cpp

@@ -7,6 +7,7 @@
 #include "array.h"
 #include "fileutil.h"
 #include "iniutil.h"
+#include "toolkit.h"
 
 #if defined(RVC_OS_LINUX)
 #include "SogouVersion.h"
@@ -128,6 +129,19 @@ void ResourceWatcherServiceSession::Handle_GetNetworkInfo(SpReqAnsContext<Resour
     m_pEntity->GetNetworkInfo(ctx);
 }
 
+void ResourceWatcherServiceSession::Handle_GetThirdPartyInstallState(SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req, ResourceWatcherService_GetThirdPartyInstallState_Ans>::Pointer ctx)
+{
+    LOG_FUNCTION();
+    m_pEntity->GetThirdPartyInstallState(ctx);
+
+}
+
+void ResourceWatcherServiceSession::Handle_InstallThirdPartyProgram(SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req, ResourceWatcherService_InstallThirdPartyProgram_Ans>::Pointer ctx)
+{
+    LOG_FUNCTION();
+    m_pEntity->InstallThirdPartyProgram(ctx);
+}
+
 void ResourceWatcherEntity::UpdateDNS(SpReqAnsContext<ResourceWatcherService_UpdateDNS_Req, ResourceWatcherService_UpdateDNS_Ans>::Pointer ctx)
 {
     ctx->Answer(Error_NotImpl);
@@ -223,6 +237,202 @@ void ResourceWatcherEntity::GetNetworkInfo(SpReqAnsContext<ResourceWatcherServic
     ctx->Answer(Error_Succeed);
 }
 
+void ResourceWatcherEntity::GetThirdPartyInstallState(SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req, ResourceWatcherService_GetThirdPartyInstallState_Ans>::Pointer ctx)
+{
+
+    ErrorCodeEnum result(Error_Succeed);
+
+    if (ctx->Req.mode == 1) {//查看搜狗输入法安装状态
+        SogouInstallInfo info;
+        info.state.dwInstalledStatus = Sogou_GetInstallStatus();
+        info.state.strInstallDate = Sogou_GetInstallTime();
+        info.program.strInstallDir = Sogou_GetInstallPath();
+        info.program.strVersion = Sogou_GetVersion();
+        Dbg("%d, %s, %s, %s"
+            , info.state.dwInstalledStatus, info.state.strInstallDate.GetData()
+            , info.program.strInstallDir.GetData(), info.program.strVersion.GetData());
+        Dbg("InstallTime: %s", info.state.GetInstallTime().ToTimeString().GetData());
+
+        ctx->Ans.status = info.IsInstalledSuccess() ? 1 : 0;
+        ctx->Ans.reserverd1 = info.state.GetInstallTime().ToTimeString();
+        ctx->Ans.path = info.program.strInstallDir;
+        ctx->Ans.version = info.program.strVersion;
+    } else {
+        result = Error_NotSupport;
+    }
+
+    ctx->Answer(result);
+    return;
+}
+
+void ResourceWatcherEntity::InstallThirdPartyProgram(SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req, ResourceWatcherService_InstallThirdPartyProgram_Ans>::Pointer ctx)
+{
+    ErrorCodeEnum result(Error_Succeed);
+    ErrorCodeEnum tmpResult(Error_Succeed);
+    CSimpleStringA tmpMsg(true);
+
+    if (ctx->Req.type == 1) {//安装搜狗输入法
+
+        Dbg("to install sogou input...");
+
+        CSimpleStringA strInstallPkgPath;
+        CSimpleStringA strAdDataDirPath(true);
+        tmpResult = GetFunction()->GetPath("Ad", strAdDataDirPath);
+        if (strAdDataDirPath.IsNullOrEmpty()) {
+            tmpResult = Error_Unexpect;
+            tmpMsg = "获取安装包路径失败";
+        } else {
+            array_header_t* subs;
+            subs = fileutil_get_sub_dirs_a(strAdDataDirPath);
+            if (subs) {
+                for (int i = 0; i < subs->nelts; ++i) {
+                    char* dir = ARRAY_IDX(subs, i, char*);
+                    const char* dirname = &dir[strAdDataDirPath.GetLength() + 1];
+                    if (CSimpleStringA(dirname).IsStartWith("sogou", true)) {
+                        Dbg("found it: %s", dir);
+                        strInstallPkgPath = dir;
+                        break;
+                    }
+                }
+                toolkit_array_free2(subs);
+            }
+
+            if (strInstallPkgPath.IsNullOrEmpty()) {
+                tmpMsg = CSimpleStringA::Format("%s 路径下找不到输入法安装包文件夹", strAdDataDirPath.GetData());
+                tmpResult = Error_NotExist;
+            } else {
+                CSimpleStringA strRunIniFilePath = strInstallPkgPath + SPLIT_SLASH_STR + "Run.ini";
+                if (ExistsFileA(strRunIniFilePath)) {
+                    char* p = inifile_read_str(strRunIniFilePath, "Action", "ToRun", "");
+                    CSimpleStringA strInstallScriptFile(strInstallPkgPath + SPLIT_SLASH_STR + p);
+                    toolkit_free(p);
+                    Dbg("RunScript file: %s", strInstallScriptFile.GetData());
+                    if (ExistsFileA(strInstallScriptFile)) {
+                        do {
+                            char app[MAX_PATH] = { '\0' };
+                            tk_process_t* process = NULL;
+                            tk_process_option_t option;
+                            option.exit_cb = NULL;
+                            option.file = NULL;
+                            option.flags = 0;
+
+                            sprintf(app, "bash %s", strInstallScriptFile.GetData());
+                            option.params = app;
+                            const int res = process_spawn(&option, &process);
+                            if (0 == res) {
+                                FREE(process);
+                                Dbg("execute {%s} suc", strInstallScriptFile.GetData());
+                            } else {
+                                tmpMsg = CSimpleStringA::Format("执行 %s 失败:%s", strInstallScriptFile.GetData(), toolkit_strerror(res));
+                                tmpResult = Error_Process;
+                            }
+
+                        } while (false);
+
+                    } else {
+                        tmpMsg = CSimpleStringA::Format("%s 执行文件不存在", strInstallScriptFile.GetData());
+                        tmpResult = Error_NotExist;
+                    }
+
+                } else {
+                    tmpMsg = CSimpleStringA::Format("%s 文件不存在", strRunIniFilePath.GetData());
+                    tmpResult = Error_NotExist;
+                }
+            }
+
+        }
+
+        if (tmpResult == Error_Succeed) {
+            Sleep(500);
+            SogouInstallInfo info;
+            info.state.dwInstalledStatus = Sogou_GetInstallStatus();
+            info.state.strInstallDate = Sogou_GetInstallTime();
+            info.program.strInstallDir = Sogou_GetInstallPath();
+            info.program.strVersion = Sogou_GetVersion();
+            Dbg("%d, %s, %s, %s"
+                , info.state.dwInstalledStatus, info.state.strInstallDate.GetData()
+                , info.program.strInstallDir.GetData(), info.program.strVersion.GetData());
+            Dbg("InstallTime: %s", info.state.GetInstallTime().ToTimeString().GetData());
+
+            if (!info.IsInstalledSuccess()) {
+                tmpResult = Error_FailVerify;
+                tmpMsg = CSimpleStringA::Format("安装成功,但检测版本信息失败!");
+            } else {
+                ctx->Ans.path = info.program.strInstallDir;
+                ctx->Ans.reserverd1 = info.program.strVersion;
+                ctx->Ans.reserverd2 = info.state.GetInstallTime().ToTimeString();
+            }
+        }
+    } else if (ctx->Req.type == 2) {//安装花了钱的字体
+
+        Dbg("to install sogou input...");
+
+        
+        CSimpleStringA strAdDataDirPath(true);
+        tmpResult = GetFunction()->GetPath("Ad", strAdDataDirPath);
+        if (strAdDataDirPath.IsNullOrEmpty()) {
+            tmpResult = Error_Unexpect;
+            tmpMsg = "获取安装包路径失败";
+        } else {
+
+            CSimpleStringA strInstallPkgPath = strAdDataDirPath + SPLIT_SLASH_STR "HYQiHei";
+            if (!ExistsDirA(strInstallPkgPath)) {
+                tmpMsg = CSimpleStringA::Format("%s 文件夹不存在", strInstallPkgPath.GetData());
+                tmpResult = Error_NotExist;
+            } else {
+                CSimpleStringA strRunIniFilePath = strInstallPkgPath + SPLIT_SLASH_STR + "Run.ini";
+                if (ExistsFileA(strRunIniFilePath)) {
+                    char* p = inifile_read_str(strRunIniFilePath, "Action", "ToRun", "");
+                    CSimpleStringA strInstallScriptFile(strInstallPkgPath + SPLIT_SLASH_STR + p);
+                    toolkit_free(p);
+                    Dbg("RunScript file: %s", strInstallScriptFile.GetData());
+                    if (ExistsFileA(strInstallScriptFile)) {
+                        do {
+                            char app[MAX_PATH] = { '\0' };
+                            tk_process_t* process = NULL;
+                            tk_process_option_t option;
+                            option.exit_cb = NULL;
+                            option.file = NULL;
+                            option.flags = 0;
+
+                            sprintf(app, "bash %s", strInstallScriptFile.GetData());
+                            option.params = app;
+                            const int res = process_spawn(&option, &process);
+                            if (0 == res) {
+                                FREE(process);
+                                Dbg("execute {%s} suc", strInstallScriptFile.GetData());
+                            } else {
+                                tmpMsg = CSimpleStringA::Format("执行 %s 失败:%s", strInstallScriptFile.GetData(), toolkit_strerror(res));
+                                tmpResult = Error_Process;
+                            }
+
+                        } while (false);
+
+                    } else {
+                        tmpMsg = CSimpleStringA::Format("%s 执行文件不存在", strInstallScriptFile.GetData());
+                        tmpResult = Error_NotExist;
+                    }
+
+                } else {
+                    tmpMsg = CSimpleStringA::Format("%s 文件不存在", strRunIniFilePath.GetData());
+                    tmpResult = Error_NotExist;
+                }
+            }
+        }
+
+        if (tmpResult == Error_Succeed) {
+            ///**TODO(Gifur@10/21/2021): 二次校验 */
+        }
+    } else {
+        result = Error_NotSupport;
+    }
+
+    ctx->Ans.result = tmpResult;
+    ctx->Ans.msg = tmpMsg;
+    ctx->Answer(result);
+    return;
+}
+
 #if defined(RVC_OS_WIN)
 //1: 32bit process running at 64bit platform
 //0: 

+ 9 - 0
Module/mod_ResourceWatcher/mod_ResourceWatcher.h

@@ -36,6 +36,9 @@ public:
 
 	virtual void Handle_GetNetworkInfo(SpReqAnsContext<ResourceWatcherService_GetNetworkInfo_Req, ResourceWatcherService_GetNetworkInfo_Ans>::Pointer ctx);
 
+	virtual void Handle_GetThirdPartyInstallState(SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req, ResourceWatcherService_GetThirdPartyInstallState_Ans>::Pointer ctx);
+
+	virtual void Handle_InstallThirdPartyProgram(SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req, ResourceWatcherService_InstallThirdPartyProgram_Ans>::Pointer ctx);
 
 private:
 	ResourceWatcherEntity* m_pEntity;
@@ -177,8 +180,14 @@ public:
 	}
 
 	void UpdateDNS(SpReqAnsContext<ResourceWatcherService_UpdateDNS_Req, ResourceWatcherService_UpdateDNS_Ans>::Pointer ctx);
+	
 	void GetNetworkInfo(SpReqAnsContext<ResourceWatcherService_GetNetworkInfo_Req, ResourceWatcherService_GetNetworkInfo_Ans>::Pointer ctx);
 
+    void GetThirdPartyInstallState(SpReqAnsContext<ResourceWatcherService_GetThirdPartyInstallState_Req, ResourceWatcherService_GetThirdPartyInstallState_Ans>::Pointer ctx);
+
+    void InstallThirdPartyProgram(SpReqAnsContext<ResourceWatcherService_InstallThirdPartyProgram_Req, ResourceWatcherService_InstallThirdPartyProgram_Ans>::Pointer ctx);
+
+
 #if defined(_MSC_VER)
     SP_BEGIN_MSG_DISPATCH_MAP(ResourceWatcherEntity)
         SP_BEGIN_ENTITY_MSG("CardSwiper")