|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
|
#include "epm_handler_common.h"
|
|
|
#include <vector>
|
|
|
#include <string>
|
|
|
#include "ocilib.h"
|
|
|
#include <map>
|
|
|
#include <string>
|
|
|
#include <iostream>
|
|
|
#include <tccore/item.h>
|
|
|
#include <curl/curl.h>
|
|
|
#include <regex>
|
|
|
#include <fstream>
|
|
|
#include <chrono>
|
|
|
#include <ctime>
|
|
|
#include <memory>
|
|
|
#include <cstring>
|
|
|
#include <sstream>
|
|
|
#include <algorithm>
|
|
|
#include <exception>
|
|
|
#define ITK_err 919821
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
|
char* concat(char** s, int size) {
|
|
|
int length = 0;
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
length += strlen(s[i]);
|
|
|
}
|
|
|
char* result = new char[length + 1];
|
|
|
int index = 0;
|
|
|
for (int i = 0; i < size; i++) {
|
|
|
int len = strlen(s[i]);
|
|
|
memcpy(result + index, s[i], len);
|
|
|
index += len;
|
|
|
}
|
|
|
result[length] = '\0';
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
// 移除字符串两端的空白字符
|
|
|
string trim(string str) {
|
|
|
str.erase(0, str.find_first_not_of(" \n\r\t"));
|
|
|
str.erase(str.find_last_not_of(" \n\r\t") + 1);
|
|
|
return str;
|
|
|
}
|
|
|
// 将字符串按照某个字符分割成多个子串
|
|
|
vector<string> split(string str, char delimiter) {
|
|
|
vector<string> tokens;
|
|
|
stringstream ss(str);
|
|
|
string token;
|
|
|
while (getline(ss, token, delimiter)) {
|
|
|
tokens.push_back(trim(token));
|
|
|
}
|
|
|
return tokens;
|
|
|
}
|
|
|
// 解析JSON字符串中的字符串值
|
|
|
string parseString(string str) {
|
|
|
str.erase(0, 1); // 移除开头的双引号
|
|
|
str.erase(str.size() - 1); // 移除结尾的双引号
|
|
|
return str;
|
|
|
}
|
|
|
// 解析JSON字符串中的整数值
|
|
|
int64_t parseInteger(string str) {
|
|
|
return stoll(trim(str));
|
|
|
}
|
|
|
void morechat(char **& values,char *& result) {
|
|
|
std::string values_str;
|
|
|
for (int i = 0; *(values + i) != nullptr; i++) { // 使用双重指针访问数组元素
|
|
|
if (i > 0) {
|
|
|
values_str += ", ";
|
|
|
}
|
|
|
values_str += *(values + i);
|
|
|
}
|
|
|
result = new char[values_str.size() + 1];
|
|
|
std::strcpy(result, values_str.c_str());
|
|
|
std::cout << result << std::endl;
|
|
|
delete[] result;
|
|
|
delete[] values; // 记得释放 char** 类型的指针数组
|
|
|
}
|
|
|
|
|
|
static size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {
|
|
|
((std::string*)userp)->append((char*)contents, size * nmemb);
|
|
|
return size * nmemb;
|
|
|
}
|
|
|
size_t writeFunction(void* ptr, size_t size, size_t nmemb, std::string* data) {
|
|
|
data->append((char*)ptr, size * nmemb);
|
|
|
return size * nmemb;
|
|
|
}
|
|
|
|
|
|
void Split(string strArg, string spliter, vector<string> &ans)
|
|
|
{
|
|
|
ans.clear();
|
|
|
size_t index0 = 0;
|
|
|
string one_arg;
|
|
|
if (strArg.find_first_not_of(' ') == string::npos)
|
|
|
strArg = "";
|
|
|
while (strArg.size() > 0)
|
|
|
{
|
|
|
index0 = strArg.find_first_of(spliter);
|
|
|
if (index0 != string::npos)
|
|
|
{
|
|
|
one_arg = strArg.substr(0, index0);
|
|
|
strArg = strArg.substr(index0 + 1);
|
|
|
ans.push_back(one_arg);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
ans.push_back(strArg);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int RB_PLM2LIMS_JCSY(EPM_action_message_t msg)
|
|
|
{
|
|
|
auto logFile = std::make_unique<std::ofstream>("D:\\TCTOLIMS\\output.log", std::ios_base::app);
|
|
|
logFile->is_open();
|
|
|
auto now = std::chrono::system_clock::now();
|
|
|
std::time_t time = std::chrono::system_clock::to_time_t(now);
|
|
|
std::string timeStr = std::ctime(&time);
|
|
|
*logFile << "[" << timeStr.substr(0, timeStr.size() - 1) << "] ";
|
|
|
*logFile << "=========================传递TC检测分析委托单信息至LIMS===================" << std::endl;
|
|
|
POM_AM__set_application_bypass(true); // 开旁路
|
|
|
*logFile << "=========================开旁路===================" << std::endl;
|
|
|
printf("=========================传递TC检测分析委托单信息至LIMS===================\n");
|
|
|
int ifail = ITK_ok;
|
|
|
int attachments_num = 0;
|
|
|
tag_t rootTask = NULLTAG, *attachments = NULLTAG;
|
|
|
//获取任务对象
|
|
|
EPM_ask_root_task(msg.task, &rootTask);
|
|
|
//获取任务目标对象
|
|
|
EPM_ask_attachments(rootTask, EPM_target_attachment, &attachments_num, &attachments);
|
|
|
//获取参数
|
|
|
char *url = NULL, *name = NULL, *password = NULL;
|
|
|
char *argflag = NULL, *argvalue = NULL, *arg = NULL;
|
|
|
int arg_cnt = TC_number_of_arguments(msg.arguments);
|
|
|
char* uid;
|
|
|
char *endResult;
|
|
|
printf("参数个数为:%d\n", arg_cnt);
|
|
|
*logFile << "参数个数为" << std::endl;
|
|
|
if (arg_cnt > 0)
|
|
|
{
|
|
|
|
|
|
for (int i = 0; i<arg_cnt; i++)
|
|
|
{
|
|
|
//获取下一个参数(从0开始)
|
|
|
arg = TC_next_argument(msg.arguments);
|
|
|
//获取参数的名称和值
|
|
|
ifail = ITK_ask_argument_named_value((const char*)arg, &argflag, &argvalue);
|
|
|
if (stricmp(argflag, "LIMS") == 0)
|
|
|
{
|
|
|
if (argvalue != NULL)
|
|
|
{
|
|
|
url = argvalue;
|
|
|
printf("获取的值%s\n", url);
|
|
|
*logFile << "获取的值1" << std::endl;
|
|
|
}
|
|
|
}
|
|
|
else if (stricmp(argflag, "NAME") == 0)
|
|
|
{
|
|
|
if (argvalue != NULL)
|
|
|
{
|
|
|
name = argvalue;
|
|
|
printf("获取的值%s\n", name);
|
|
|
*logFile << "获取的值2" << std::endl;
|
|
|
}
|
|
|
}
|
|
|
else if (stricmp(argflag, "PASSWORD") == 0)
|
|
|
{
|
|
|
if (argvalue != NULL)
|
|
|
{
|
|
|
password = argvalue;
|
|
|
printf("获取的值%s\n", password);
|
|
|
*logFile << "获取的值3" << std::endl;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
//调整 获取流程uid,保证数据的唯一性
|
|
|
|
|
|
ITK__convert_tag_to_uid(rootTask, &uid);
|
|
|
|
|
|
//调整,一次性发送多条数据
|
|
|
//弹窗提示
|
|
|
const char* error = "";
|
|
|
string mees = "";
|
|
|
for (int r = 0; r < attachments_num;r++) {
|
|
|
//记录传递对象
|
|
|
char* itemObjId;
|
|
|
AOM_ask_value_string(attachments[r], "item_id", &itemObjId);
|
|
|
*logFile << "************************************开始执行对象" << itemObjId << "************************************" << std::endl;
|
|
|
//获取首选项
|
|
|
std::map<std::string, std::string> valueMap;//统计集合
|
|
|
//orderList
|
|
|
std::map<std::string, std::string> orderValue;
|
|
|
std::map<std::string, std::map<std::string, std::string>> orderMap;
|
|
|
//根据首选项获取属性
|
|
|
*logFile << "根据首选项RB_PLM2LIMS_JCSY获取属性" << std::endl;
|
|
|
printf("根据首选项RB_PLM2LIMS_JCSY获取属性\n");
|
|
|
int pref_cnt = 0;
|
|
|
char** pref_vals = NULL;
|
|
|
//获取首选项的值
|
|
|
PREF_ask_char_values("RB_PLM2LIMS_JCSY", &pref_cnt, &pref_vals);
|
|
|
if (pref_cnt > 0) {
|
|
|
for (int i = 0; i < pref_cnt; i++) {
|
|
|
char* getValue = "";
|
|
|
char* val = pref_vals[i];
|
|
|
*logFile << "开始分割字符串" << std::endl;
|
|
|
*logFile << val << std::endl;
|
|
|
printf("开始分割首选项%s\n", val);
|
|
|
printf("开始分割字符串\n");
|
|
|
vector<string> ans;
|
|
|
Split(val, "-", ans);
|
|
|
if (ans.size() > 0) {
|
|
|
for (int j = 0; j < ans.size(); j++) {
|
|
|
if (stricmp("true", (char*)ans[2].c_str()) == 0) { //是lov属性
|
|
|
*logFile << "是lov属性" << std::endl;
|
|
|
//Log::info("是lov属性");
|
|
|
if (stricmp("true", (char*)ans[3].c_str()) == 0) { //传递真实值
|
|
|
*logFile << "传递真实值" << std::endl;
|
|
|
//Log::info("传递真实值");
|
|
|
if (stricmp("true", (char*)ans[4].c_str()) == 0) { //封装进orderList
|
|
|
*logFile << "封装进orderList" << std::endl;
|
|
|
//Log::info("封装进orderList");
|
|
|
int call;
|
|
|
if (stricmp(ans[5].c_str(), "string") == 0) {
|
|
|
*logFile << "获取到了字符串" << std::endl;
|
|
|
ITKCALL(call = AOM_ask_value_string(attachments[r], ans[1].c_str(), &getValue));
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "date") == 0) {
|
|
|
*logFile << "获取到了日期" << std::endl;
|
|
|
date_t getdate;
|
|
|
ITKCALL(call = AOM_ask_value_date(attachments[r], ans[1].c_str(), &getdate));
|
|
|
sprintf(getValue, "%d-%02d-%02d 00:00", getdate.year, getdate.month + 1, getdate.day);
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "array") == 0) {
|
|
|
*logFile << "获取到了数组" << std::endl;
|
|
|
int num; char** getValues;
|
|
|
ITKCALL(call = AOM_ask_value_strings(attachments[r], ans[1].c_str(), &num, &getValues));
|
|
|
getValue = concat(getValues, num);
|
|
|
}
|
|
|
else {
|
|
|
getValue = "***";
|
|
|
}
|
|
|
orderValue[ans[0].c_str()] = getValue;
|
|
|
}
|
|
|
else { //不封装进orderList
|
|
|
//Log::info("不封装进orderList");
|
|
|
*logFile << "不封装进orderList" << std::endl;
|
|
|
int call;
|
|
|
if (stricmp(ans[5].c_str(), "string") == 0) {
|
|
|
*logFile << "获取到了字符串" << std::endl;
|
|
|
ITKCALL(call = AOM_ask_value_string(attachments[r], ans[1].c_str(), &getValue));
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "date") == 0) {
|
|
|
*logFile << "获取到了日期" << std::endl;
|
|
|
date_t getdate;
|
|
|
ITKCALL(call = AOM_ask_value_date(attachments[r], ans[1].c_str(), &getdate));
|
|
|
sprintf(getValue, "%d-%02d-%02d 00:00", getdate.year, getdate.month + 1, getdate.day);
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "array") == 0) {
|
|
|
*logFile << "获取到了数组" << std::endl;
|
|
|
int num; char** getValues;
|
|
|
ITKCALL(call = AOM_ask_value_strings(attachments[r], ans[1].c_str(), &num, &getValues));
|
|
|
getValue = concat(getValues, num);
|
|
|
}
|
|
|
else {
|
|
|
getValue = "***";
|
|
|
}
|
|
|
valueMap[ans[0].c_str()] = getValue;
|
|
|
}
|
|
|
}
|
|
|
else { //传递显示值
|
|
|
*logFile << "传递显示值" << std::endl;
|
|
|
//Log::info("传递显示值");
|
|
|
if (stricmp("true", (char*)ans[4].c_str()) == 0) { //封装进orderList
|
|
|
*logFile << "封装进orderList" << std::endl;
|
|
|
//Log::info("封装进orderList");
|
|
|
int call;
|
|
|
if (stricmp(ans[5].c_str(), "string") == 0) {
|
|
|
*logFile << "获取到了字符串" << std::endl;
|
|
|
ITKCALL(call = AOM_UIF_ask_value(attachments[r], ans[1].c_str(), &getValue));
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "array") == 0) {
|
|
|
*logFile << "获取到了数组" << std::endl;
|
|
|
int num; char** getValues;
|
|
|
ITKCALL(call = AOM_UIF_ask_values(attachments[r], ans[1].c_str(), &num, &getValues));
|
|
|
getValue = concat(getValues, num);
|
|
|
}
|
|
|
else {
|
|
|
getValue = "***";
|
|
|
}
|
|
|
orderValue[ans[0].c_str()] = getValue;
|
|
|
}
|
|
|
else { //不封装进orderList
|
|
|
*logFile << "不封装进orderList" << std::endl;
|
|
|
//Log::info("不封装进orderList");
|
|
|
int call;
|
|
|
if (stricmp(ans[5].c_str(), "string") == 0) {
|
|
|
*logFile << "获取到了字符串" << std::endl;
|
|
|
ITKCALL(call = AOM_UIF_ask_value(attachments[r], ans[1].c_str(), &getValue));
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "array") == 0) {
|
|
|
*logFile << "获取到了数组" << std::endl;
|
|
|
int num; char** getValues;
|
|
|
ITKCALL(call = AOM_UIF_ask_values(attachments[r], ans[1].c_str(), &num, &getValues));
|
|
|
getValue = concat(getValues, num);
|
|
|
}
|
|
|
else {
|
|
|
getValue = "***";
|
|
|
}
|
|
|
valueMap[ans[0].c_str()] = getValue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else { //不是lov属性
|
|
|
*logFile << "不是lov属性" << std::endl;
|
|
|
//Log::info("不是lov属性");
|
|
|
if (stricmp("true", (char*)ans[4].c_str()) == 0) { //封装进orderList
|
|
|
*logFile << "封装进orderList" << std::endl;
|
|
|
//Log::info("封装进orderList");
|
|
|
int call;
|
|
|
if (stricmp(ans[5].c_str(), "string") == 0) {
|
|
|
*logFile << "获取到了字符串" << std::endl;
|
|
|
ITKCALL(call = AOM_ask_value_string(attachments[r], ans[1].c_str(), &getValue));
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "date") == 0) {
|
|
|
*logFile << "获取到了日期" << std::endl;
|
|
|
date_t getdate;
|
|
|
*logFile << "开始赋值" << std::endl;
|
|
|
ITKCALL(call = AOM_ask_value_date(attachments[r], ans[1].c_str(), &getdate));
|
|
|
*logFile << "赋值结束" << std::endl;
|
|
|
printf("getdate %d", getdate);
|
|
|
char fileDate[128] = "";
|
|
|
sprintf_s(fileDate, "%04d-%02d-%02d 00:00", getdate.year, getdate.month + 1, getdate.day);
|
|
|
*logFile << "赋值成功" << std::endl;
|
|
|
*logFile << fileDate << std::endl;
|
|
|
getValue = fileDate;
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "array") == 0) {
|
|
|
*logFile << "获取到了数组" << std::endl;
|
|
|
int num; char** getValues;
|
|
|
ITKCALL(call = AOM_ask_value_strings(attachments[r], ans[1].c_str(), &num, &getValues));
|
|
|
getValue = concat(getValues, num);
|
|
|
}
|
|
|
else {
|
|
|
getValue = "***";
|
|
|
}
|
|
|
orderValue[ans[0].c_str()] = getValue;
|
|
|
}
|
|
|
else { //不封装进orderList
|
|
|
//Log::info("不封装进orderList");
|
|
|
*logFile << "不封装进orderList" << std::endl;
|
|
|
int call;
|
|
|
if (stricmp(ans[5].c_str(), "string") == 0) {
|
|
|
*logFile << "获取到了字符串" << std::endl;
|
|
|
ITKCALL(call = AOM_ask_value_string(attachments[r], ans[1].c_str(), &getValue));
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "date") == 0) {
|
|
|
*logFile << "获取到了日期" << std::endl;
|
|
|
date_t getdate;
|
|
|
*logFile << "开始赋值" << std::endl;
|
|
|
ITKCALL(call = AOM_ask_value_date(attachments[r], ans[1].c_str(), &getdate));
|
|
|
*logFile << "赋值结束" << std::endl;
|
|
|
printf("getdate %d", &getdate);
|
|
|
|
|
|
char fileDate[128] = "";
|
|
|
sprintf_s(fileDate, "%04d-%02d-%02d 00:00", getdate.year, getdate.month + 1, getdate.day);
|
|
|
*logFile << "赋值成功" << std::endl;
|
|
|
*logFile << fileDate << std::endl;
|
|
|
getValue = fileDate;
|
|
|
}
|
|
|
else if (stricmp(ans[5].c_str(), "array") == 0) {
|
|
|
*logFile << "获取到了数组" << std::endl;
|
|
|
int num; char** getValues;
|
|
|
ITKCALL(call = AOM_ask_value_strings(attachments[r], ans[1].c_str(), &num, &getValues));
|
|
|
getValue = concat(getValues, num);
|
|
|
}
|
|
|
else {
|
|
|
getValue = "***";
|
|
|
}
|
|
|
valueMap[ans[0].c_str()] = getValue;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
//将orderList整合
|
|
|
*logFile << "将orderList整合" << std::endl;
|
|
|
//Log::info("将orderList整合");
|
|
|
orderMap["orderList"] = orderValue;
|
|
|
//整合json
|
|
|
std::string jsonStr = "[{";
|
|
|
// 添加valueMap的值到JSON字符串
|
|
|
for (auto it = valueMap.begin(); it != valueMap.end(); it++) {
|
|
|
jsonStr += "\"" + it->first + "\":\"" + it->second + "\",";
|
|
|
}
|
|
|
// 添加orderMap的值到JSON字符串
|
|
|
for (auto it = orderMap.begin(); it != orderMap.end(); it++) {
|
|
|
std::map<std::string, std::string> order = it->second;
|
|
|
jsonStr += "\"" + it->first + "\":[{";
|
|
|
for (auto it2 = order.begin(); it2 != order.end(); it2++) {
|
|
|
jsonStr += "\"" + it2->first + "\":\"" + it2->second + "\",";
|
|
|
}
|
|
|
if (order.size() > 0) {
|
|
|
jsonStr.erase(jsonStr.end() - 1);
|
|
|
}
|
|
|
jsonStr += "},";
|
|
|
}
|
|
|
if (orderMap.size() > 0) {
|
|
|
jsonStr.erase(jsonStr.end() - 1);
|
|
|
}
|
|
|
jsonStr += "]}]";
|
|
|
// 输出JSON字符串
|
|
|
std::cout << jsonStr << std::endl;
|
|
|
|
|
|
|
|
|
//将json存储至本地
|
|
|
char jsonFile[1024] = "";
|
|
|
strcat(jsonFile, "D:\\TCTOLIMS\\");
|
|
|
strcat(jsonFile, uid);
|
|
|
strcat(jsonFile, "output.json");
|
|
|
FILE* jsFile = fopen(jsonFile, "a+");
|
|
|
|
|
|
if (jsFile == NULL) {
|
|
|
// 文件不存在或者无法打开,尝试创建
|
|
|
*logFile << "文件不存在或者无法打开,开始创建" << std::endl;
|
|
|
if (errno != EEXIST) {
|
|
|
return EXIT_FAILURE;
|
|
|
}
|
|
|
|
|
|
jsFile = fopen(jsonFile, "w");
|
|
|
if (jsFile == NULL) {
|
|
|
return EXIT_FAILURE;
|
|
|
}
|
|
|
*logFile << "文件创建成功,开始写入信息" << std::endl;
|
|
|
}
|
|
|
else {
|
|
|
*logFile << "文件已存在,开始写入信息" << std::endl;
|
|
|
fclose(jsFile);
|
|
|
}
|
|
|
|
|
|
std::ofstream ofs(jsonFile);
|
|
|
ofs << jsonStr;
|
|
|
ofs.close();
|
|
|
*logFile << "保存成功" << std::endl;
|
|
|
//使用java发送请求给接口
|
|
|
printf("开始执行cmd方法");
|
|
|
*logFile << "开始执行cmd方法" << std::endl;
|
|
|
char cmd[1024] = "";
|
|
|
strcpy(cmd, "java -jar D:\\Siemens\\Teamcenter12\\bin\\PostMain.jar");
|
|
|
strcat(cmd, " ");
|
|
|
strcat(cmd, url);
|
|
|
strcat(cmd, " ");
|
|
|
strcat(cmd, uid);
|
|
|
*logFile << cmd << std::endl;
|
|
|
printf("\n%s\n", cmd);
|
|
|
system(cmd);
|
|
|
*logFile << "cmd执行完毕" << std::endl;
|
|
|
//读取本地的result文件
|
|
|
string prefix = "D:\\TCTOLIMS\\";
|
|
|
string suffix = "result.txt";
|
|
|
string namepath = prefix +uid+ suffix;
|
|
|
*logFile << "读取LIMS返回文件:" << namepath << std::endl;
|
|
|
std::ifstream file1(namepath);
|
|
|
if (!file1.is_open()) {
|
|
|
std::cerr << "Failed to open file!" << std::endl;
|
|
|
char* error = "服务未响应";
|
|
|
EMH_store_error_s2(EMH_severity_error, ITK_err, "提示", error);
|
|
|
return 1;
|
|
|
}
|
|
|
std::stringstream buffer1;
|
|
|
buffer1 << file1.rdbuf();
|
|
|
std::string resultStr = buffer1.str();
|
|
|
*logFile << resultStr << std::endl;
|
|
|
if (resultStr.find("false") != std::string::npos) {
|
|
|
//写入属性值
|
|
|
AOM_lock(attachments[r]);
|
|
|
AOM_set_value_string(attachments[r], "rb3_limsInfo", resultStr.c_str());
|
|
|
AOM_save(attachments[r]);
|
|
|
AOM_unlock(attachments[r]);
|
|
|
mees = mees + resultStr+"\n";
|
|
|
|
|
|
}
|
|
|
else {
|
|
|
//写入属性值
|
|
|
AOM_lock(attachments[r]);
|
|
|
AOM_set_value_string(attachments[r], "rb3_limsInfo", resultStr.c_str());
|
|
|
AOM_save(attachments[r]);
|
|
|
AOM_unlock(attachments[r]);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
POM_AM__set_application_bypass(false); // 关旁路
|
|
|
if (strcmp("",mees.c_str())!=0) {
|
|
|
EMH_store_error_s2(EMH_severity_error, ITK_err, "提示", mees.c_str());
|
|
|
return 1;
|
|
|
}
|
|
|
else {
|
|
|
return ITK_ok;
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
return 0;
|
|
|
} |