package com.jdt.fedlearn.coordinator.train;

import com.jdt.fedlearn.common.constant.ResponseConstant;
import com.jdt.fedlearn.common.entity.project.MatchPartnerInfo;
import com.jdt.fedlearn.common.enums.RunningType;
import com.jdt.fedlearn.tools.serializer.JsonUtil;
import com.jdt.fedlearn.coordinator.dao.db.MatchMapper;
import com.jdt.fedlearn.coordinator.entity.table.MatchEntity;
import com.jdt.fedlearn.coordinator.entity.table.TrainInfo;
import com.jdt.fedlearn.coordinator.entity.train.TrainContext;
import com.jdt.fedlearn.coordinator.util.ConfigUtil;
import com.jdt.fedlearn.coordinator.network.SendAndRecv;
import com.jdt.fedlearn.common.entity.core.ClientInfo;
import com.jdt.fedlearn.common.entity.core.Message;
import com.jdt.fedlearn.core.entity.base.SingleElement;
import com.jdt.fedlearn.core.entity.boost.*;
import com.jdt.fedlearn.core.entity.common.CommonRequest;
import com.jdt.fedlearn.core.entity.common.CommonResponse;
import com.jdt.fedlearn.core.entity.common.MetricValue;
import com.jdt.fedlearn.core.psi.MatchResult;
import com.jdt.fedlearn.common.entity.core.type.AlgorithmType;
import com.jdt.fedlearn.core.type.MetricType;
import com.jdt.fedlearn.coordinator.dao.db.TrainMapper;
import com.jdt.fedlearn.coordinator.service.prepare.MatchStartImpl;
import com.jdt.fedlearn.coordinator.service.train.TrainCommonServiceImpl;
import com.jdt.fedlearn.coordinator.service.train.TrainStartServiceImpl;
import com.jdt.fedlearn.core.type.data.Pair;
import com.jdt.fedlearn.core.type.data.StringTuple2;
import mockit.Mock;
import mockit.MockUp;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.*;

public class TrainTest {

    private static ClientInfo C1;
    private static ClientInfo C2;
    private static ClientInfo C3;

    private static final Random random = new Random();

    @BeforeClass
    public void init() {
        initClientInfo();
        mockConfigInit();
        mockPostClientInfo();
        mockInsertTrainInfo();
        mockUpdateTrainInfo();
        mockisContainMatchModel();
    }

    private void initClientInfo() {
        C1 = new ClientInfo("127.0.0.1", 8094, "http");
        C2 = new ClientInfo("127.0.0.1", 8090, "http");
        C3 = new ClientInfo("127.0.0.1", 8088, "http");
    }

    private static final String TASK_ID = "taskId";

    @Test(invocationCount = 2, threadPoolSize = 2)
    public void train() throws InterruptedException {
        // TODO 现在每一次都相当于是使用同样的mock的数据，也就是前面uids的随机过程对后续训练没有影响，是否有办法将二者结合。
        String taskId = "10030";
        String[] ids = {"1B","2A","3A","4A","5C","6C","7C","8B","9B","10B"};
        int count = random.nextInt(ids.length) + 1;
        System.out.println("训练uid个数={}" + count);
        String[] uids = randomUids(ids, count);
        // map client and uid information stored in MappingResult
        Map<ClientInfo, MatchResult> sumList = new HashMap<>();
        Map<Long, String> idMap = new HashMap<>();
        for (int i = 0; i < uids.length; i++) {
            idMap.put(Long.parseLong(String.valueOf(i)), uids[i]);
        }
        String matchId = "10030-MD5-210823112246";
        MatchResult matchResult = new MatchResult(matchId, 10, "report");
        sumList.put(C1, matchResult);
        sumList.put(C2, matchResult);
        sumList.put(C3, matchResult);
        String matchReport = "IdMatch is complete!! \n" + " Match num is 10";
        List<MatchPartnerInfo> matchPartnerInfos = new ArrayList<>();
        matchPartnerInfos.add(new MatchPartnerInfo(C1.url(), "class0_train_sub.csv", "uid"));
        matchPartnerInfos.add(new MatchPartnerInfo(C2.url(), "class1_train_sub.csv", "uid"));
        matchPartnerInfos.add(new MatchPartnerInfo(C3.url(), "class2_train_sub.csv", "uid"));

        MatchEntity matchEntity = new MatchEntity(taskId, matchId, ids.length, matchReport, RunningType.COMPLETE,  matchPartnerInfos);
        MatchStartImpl.matchEntityMap.put(matchId, matchEntity);


        String content = "{\"taskId\": \"10030\", \"model\": \"FederatedGB\", \"matchId\": \"10030-MD5-210823112246\", \"algorithmParams\": [{\"field\": \"numBoostRound\", \"name\": \"\\u6811\\u7684\\u4e2a\\u6570\", \"value\": 1, \"describe\": [\"1\", \"100\"], \"defaultValue\": \"50\", \"type\": \"NUMS\"}, {\"field\": \"firstRoundPred\", \"name\": \"\\u521d\\u59cb\\u5316\\u9884\\u6d4b\\u503c\", \"value\": \"AVG\", \"describe\": [\"AVG\", \"ZERO\", \"RANDOM\"], \"defaultValue\": \"0.0\", \"type\": \"NUMS\"}, {\"field\": \"maximize\", \"name\": \"maximize\", \"value\": \"true\", \"describe\": [\"true\", \"false\"], \"defaultValue\": \"true\", \"type\": \"STRING\"}, {\"field\": \"rowSample\", \"name\": \"\\u6837\\u672c\\u62bd\\u6837\\u6bd4\\u4f8b\", \"value\": 0.4847058885077442, \"describe\": [\"0.1\", \"1.0\"], \"defaultValue\": \"1.0\", \"type\": \"NUMS\"}, {\"field\": \"colSample\", \"name\": \"\\u5217\\u62bd\\u6837\\u6bd4\\u4f8b\", \"value\": 0.46449792654461225, \"describe\": [\"0.1\", \"1.0\"], \"defaultValue\": \"1.0\", \"type\": \"NUMS\"}, {\"field\": \"earlyStoppingRound\", \"name\": \"\\u65e9\\u505c\\u8f6e\\u6570\", \"value\": 10, \"describe\": [\"1\", \"20\"], \"defaultValue\": \"10\", \"type\": \"NUMS\"}, {\"field\": \"minChildWeight\", \"name\": \"min_child_weight\", \"value\": 1, \"describe\": [\"1\", \"10\"], \"defaultValue\": \"1\", \"type\": \"NUMS\"}, {\"field\": \"minSampleSplit\", \"name\": \"min_sample_split\", \"value\": 12, \"describe\": [\"1\", \"20\"], \"defaultValue\": \"10\", \"type\": \"NUMS\"}, {\"field\": \"lambda\", \"name\": \"lambda\", \"value\": 4, \"describe\": [\"1\", \"20\"], \"defaultValue\": \"1\", \"type\": \"NUMS\"}, {\"field\": \"gamma\", \"name\": \"gamma\", \"value\": 60, \"describe\": [\"0\", \"1\"], \"defaultValue\": \"0\", \"type\": \"NUMS\"}, {\"field\": \"scalePosWeight\", \"name\": \"scale_pos_weight\", \"value\": 1, \"describe\": [\"0\", \"1\"], \"defaultValue\": \"1\", \"type\": \"NUMS\"}, {\"field\": \"numBin\", \"name\": \"\\u7279\\u5f81\\u5206\\u6876\\u4e2a\\u6570\", \"value\": 84, \"describe\": [\"33\", \"50\"], \"defaultValue\": \"33\", \"type\": \"NUMS\"}, {\"field\": \"evalMetric\", \"name\": \"eval_metric\", \"value\": [\"AUC\"], \"describe\": [\"RMSE\", \"MAPE\", \"MSE\", \"F1\", \"ACC\", \"AUC\", \"RECALL\", \"PRECISION\"], \"defaultValue\": \"RMSE\", \"type\": \"MULTI\"}, {\"field\": \"maxDepth\", \"name\": \"max_depth\", \"value\": 4, \"describe\": [\"5\", \"20\"], \"defaultValue\": \"7\", \"type\": \"NUMS\"}, {\"field\": \"eta\", \"name\": \"learning rate\", \"value\": 0.1, \"describe\": [\"0.01\", \"1\"], \"defaultValue\": \"0.3\", \"type\": \"NUMS\"}, {\"field\": \"objective\", \"name\": \"objective\", \"value\": \"binaryLogistic\", \"describe\": [\"reg:logistic\", \"reg:square\", \"count:poisson\", \"binary:logistic\"], \"defaultValue\": \"count:poisson\", \"type\": \"STRING\"}, {\"field\": \"numClass\", \"name\": \"(\\u4ec5\\u591a\\u5206\\u7c7b\\u95ee\\u9898)\\u7c7b\\u522b\\u6570\\u91cf\", \"value\": 1, \"defaultValue\": \"1\", \"describe\": [\"1\", \"100\"], \"type\": \"NUMS\"}, {\"field\": \"bitLength\", \"name\": \"\\u540c\\u6001\\u52a0\\u5bc6\\u6bd4\\u7279\\u6570\", \"value\": \"bit1024\", \"defaultValue\": \"1024\", \"describe\": [\"512\", \"1024\", \"2048\"], \"type\": \"STRING\"}, {\"field\": \"catFeatures\", \"name\": \"cat_features\", \"value\": \"1\", \"describe\": [], \"defaultValue\": \"\", \"type\": \"STRING\"}, {\"field\": \"randomizedResponseProbability\", \"name\": \"randomized_response_probability\", \"value\": 0, \"describe\": [\"0\", \"1\"], \"defaultValue\": \"0\", \"type\": \"NUMS\"}, {\"field\": \"differentialPrivacyParameter\", \"name\": \"differential_privacy_parameter\", \"value\": 0, \"describe\": [\"0\", \"1\"], \"defaultValue\": \"0\", \"type\": \"NUMS\"}, {\"field\": \"label\", \"name\": \"\\u9884\\u6d4b\\u6807\\u7b7e\", \"value\": \"y\", \"describe\": [\"uid\", \"39\", \"y\"], \"defaultValue\": \"y\", \"type\": \"STRING\"}, {\"field\": \"crossValidation\", \"name\": \"\\u4ea4\\u53c9\\u9a8c\\u8bc1\\u53c2\\u6570\", \"value\": 1.0, \"defaultValue\": 0.7, \"describe\": [\"0.0\", \"1.0\"], \"type\": \"NUMS\"}], \"clientList\": [{\"url\": \"http://127.0.0.1:8094\", \"dataset\": \"class0_train_sub.csv\", \"features\": {\"featureList\": [{\"name\": \"uid\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"job\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"previous\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"balance\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"education\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"campaign\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"poutcome\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"y\", \"type\": \"float\", \"frequency\": 1}], \"index\": \"uid\"}}, {\"url\": \"http://127.0.0.1:8090\", \"dataset\": \"class1_train_sub.csv\", \"features\": {\"featureList\": [{\"name\": \"uid\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"housing\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"default\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"month\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"age\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"duration\", \"type\": \"float\", \"frequency\": 1}], \"index\": \"uid\"}}, {\"url\": \"http://127.0.0.1:8088\", \"dataset\": \"class2_train_sub.csv\", \"features\": {\"featureList\": [{\"name\": \"uid\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"marital\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"contact\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"day\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"loan\", \"type\": \"float\", \"frequency\": 1}, {\"name\": \"pdays\", \"type\": \"float\", \"frequency\": 1}], \"index\": \"uid\"}}]}";
        Map map = JsonUtil.json2Object(content, Map.class);
        map.put(TASK_ID, taskId);
        content = JsonUtil.object2json(map);
        TrainStartServiceImpl trainStartService = new TrainStartServiceImpl();
        Map<String, Object> result = trainStartService.service(content); // 启动一个线程
        // 刷新查询模型的进度
        String modelToken = (String) ((Map)(result.get(ResponseConstant.DATA))).get("modelToken");
//        String modelToken = (String) ((HashMap)result.get(RequestConstant.DATA)).get("modelToken");
        System.out.println(modelToken);
        try {
            TrainContext trainContext = TrainCommonServiceImpl.trainContextMap.get(modelToken);
        } catch (NullPointerException e) {
            System.out.println("trainContextMap里不存在"+modelToken);
        }
        // 确定当前modelToken存在后, 循环查询模型进度直至modelToken被移除
        boolean flag = true;
        while (flag) {
            Thread.sleep(500l);
            // 训练完成后trainContextMap会移除当前modelToken -> java.lang.NullPointerException
            if (TrainCommonServiceImpl.trainContextMap.get(modelToken) != null) {
                TrainContext trainContext = TrainCommonServiceImpl.trainContextMap.get(modelToken);
                StringBuilder sbi = new StringBuilder();
                Arrays.stream(trainContext.getRunningType().getRunningType().split("")).forEach(sbi::append);
                System.out.println("训练返回结果: " + sbi.toString());
                if (sbi.toString().contains("complete")) {
                    flag = false;
                    Assert.assertEquals("complete", trainContext.getRunningType().getRunningType());
                    Assert.assertTrue(100d == trainContext.getPercent());
                } else {
                    System.out.println("训练已经完成了" + trainContext.getPercent() + "%");
                }
            } else {
                flag = false;
                System.out.println("模型训练完成");
            }
        }
    }

    private void mockConfigInit() {
        new MockUp<ConfigUtil>() {
            @Mock
            public boolean getSplitTag() {
                return true;
            }

            @Mock
            public boolean getZipProperties() {
                return true;
            }

            @Mock
            public boolean getJdChainAvailable() {
                return false;
            }

            @Mock
            public String getNetworkType(){
                return "";
            }
        };
    }

    /**
     * 模拟各个client端federatedGBModel各个训练阶段的返回结果
     */
    private void mockPostClientInfo() {
        new MockUp<SendAndRecv>() {
            @Mock
            public List<CommonResponse> broadcastTrain(List<CommonRequest> requests, String modelToken, AlgorithmType algorithm, RunningType status, String reqNum, List<String> dataset) {
                List<CommonResponse> list = new ArrayList<>();
                int phase = requests.get(0).getPhase();
                if (phase == 0) {
                    // 训练phase0时运行的是初始化阶段，各个client端返回结果为SingleElement
                    Message message = new SingleElement("init_success");
                    CommonResponse commonResponse = new CommonResponse(C1, message);
                    CommonResponse commonResponse1 = new CommonResponse(C2, message);
                    CommonResponse commonResponse2 = new CommonResponse(C3, message);
                    list.add(commonResponse);
                    list.add(commonResponse1);
                    list.add(commonResponse2);
                    return list;
                } else if (phase == 1) {
                    // 训练phase1，主动方返回当前节点的instance space以及各个instance加密后的g和h，公钥以及是否是新树（新的训练轮）
                    EncryptedGradHess encryptedGradHess = new EncryptedGradHess(C1, new int[]{0,1,2,3,4,5,6,7,8,9}, new StringTuple2[]{new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14")},
                            "93596785886705338810313824115750315693107199671143963225003100297944633680600627410088765710001436817009947832532588139375184968024736270524486273025995469801071798401881850650630717614455175952745652738824848605282494052129404449281327504175654344328824118645290919352156887907122715685911281990515694415773:true", true);
                    CommonResponse commonResponse = new CommonResponse(C1, encryptedGradHess);
                    EncryptedGradHess encryptedGradHess1 = new EncryptedGradHess(C2, null, null, null, false);
                    EncryptedGradHess encryptedGradHess2 = new EncryptedGradHess(C2, null, null, null, false);
                    CommonResponse commonResponse1 = new CommonResponse(C2, encryptedGradHess1);
                    CommonResponse commonResponse2 = new CommonResponse(C3, encryptedGradHess2);
                    list.add(commonResponse);
                    list.add(commonResponse1);
                    list.add(commonResponse2);
                    return list;
                } else if (phase == 2) {
                    // 训练phase2，主动方返回空，各个被动方client接受前一轮加密后的g和h信息后，在本地将各个特征分桶计算每一个可能分裂的left branch的gSum和hSum
                    BoostP2Res boostP2Res = new BoostP2Res(null);
                    CommonResponse commonResponse21 = new CommonResponse(C1, boostP2Res);
                    BoostP2Res boostP2Res1 = new BoostP2Res(new FeatureLeftGH[]{new FeatureLeftGH(C2, "1", new StringTuple2[]{
                            new StringTuple2("1318904153572963869720855013428427139685086646735384947127621385368328168390922373890335654117296875287204313304983734827877631757857698612070408096469994503759877054865239189090182599069821728754427972895089044305131818277563499122926648964796147347475661327354164226404607445511563511243850948694722658154133133274968337802984429716046656007053762502826355243472618829468676472248126947827317276798470725847094430692299601873347123445409172463569400538940978652510334965022915769304892099915604304701811055874347869818177574144364715909857002047713172974499600507184637818653195469806552832878711393364531891180772:-14", "7253575989422730562959115793291331892837198900118591452998904403282837333715105706560026781364514110245502748927180010114531755411238986072027864429282359274980086855746709184585453955361320066039238924427741281990409037081123657232976219455235685786778383352538326322431563531970308865245720825648066967711337142596898320225397930050877112913551489623149355608083196270434931582945850115369769328775399896126298906334005833896760436167708814522946907347805309028516887174082095259905881902060934434073334730311919335530798167068340659462988342844634165695738656495797013885055307859873436946372766472885479445604488:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("5402644788252011292640985895813290272771324035745725442190573260692993339756837220534105166514989343332938105853284474768363855989550366312399541829493661772547433640739982419278840212449316272493463153908669818535127971089641187655845005022325900258498010604840019544738212701574280490368666343061746876711221794076918306759645076427073775633136943698942125599854357332031959701703618001651709974162040354306903691339576817665613244603221609704970383644531140562966623056873929213438173345261189172712857465713065107740365400322709920281706234726221763422204058439910963359153224471765564719675181787385704410213508:-14", "8108085766872365459152997167199980021232699991224879523567112441701207738330801575923679338818865570605678033083617957958682303811943540377842190969653630064953593193379734350058988045884889858728872066120557129048079680438908444927536076449787848434408612302648465492960084359832448259493657839998798918647142823771707658463782574738996285863593227238761536658950721418883550115641220013092430557141643032628747275155317906267645481381502719409198966172859673549232412435712362069563990497781161338735260023589912302209263530041843745302746832838118951283424391155938506327420766444312688442597359704672792939583018:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14")
                    }), new FeatureLeftGH(C2, "2", new StringTuple2[]{
                            new StringTuple2("6545555311387268273383383680184271706636598461281753812518962080040565750336865360931438368287443882980727851911716921710482861806095261883657524963689089277082259843332355265732230753487610625466428070349574867777237317198556652889327189091370265689398109492747539659941752155808391293416011882357957496109762797347715375150645737177043480028051381264920314094612504705988713086781125039967477082624078750956986568998112833485819856459207724472683252291809640409060660017005246601509786702380328112041952594900596664001578166620120355385141895127573142149287818022146840658631873983306123957148511656216923087881476:-14", "6764001512251495591855902361096735163106163298170282498523649179159668334765607013460307726225457132528704046974097269934697635085016208679962156330455102821222723686372996453264447182311477517610960983488370339885602569033853049115341691549117908634107670619992341949178828877123502103637007814305267588752349721326267746042624266904644520312031615805870998410270035131027562740614090029571802648129237634382654773821185701948357835690303180661609386602042194636556973778927101082708472982702608926093114638909954439205644652102157005113458433025604413734984515707450578683289731760346430502309760013357361630645582:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                    })});
                    BoostP2Res boostP2Res2 = new BoostP2Res(new FeatureLeftGH[]{new FeatureLeftGH(C3, "1", new StringTuple2[]{
                            new StringTuple2("6588441316153248392936932217661820891783621576005485949044987287806428034216645460219802851117981555825327622881827256520598680028602246961640171302776124214881846481774393612779416988525331565756175283212606127449263189583119896546336267645415881021996876703101849149692108081832526451589862910047834472669622301105183524753286330368124852135059137385605651663524042748603385216594012344493512414218820929311096978248108604349550050807151850018021424929919289736484609824525737140277097889061473782136957058275072601230244670503243644953684975351116159358190707911490523552917505192878343613087213009546853948438627:-14", "3942202448061139955129061566490082039834939064153494295208692288942769883518938811098440000028398993719185101742198684142453918854647849528539356968112370033884894722393115121689124042409130300696564064416678073184646842165318610933172673499129448181626932435428336477754423477523865577206412552968323233897729500326187029467736172337197883082063320509941543342017394726216884798011488036034718290314149185006296355676008038554282371704282352599759701461245848606666208586995148447272243730269058913035604904529257067652731362856286453626999895115269703293713500767059209510028839730934936649804494631618502668848266:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                    }), new FeatureLeftGH(C3, "2", new StringTuple2[]{
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                    }), new FeatureLeftGH(C3, "3", new StringTuple2[]{
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                    }),new FeatureLeftGH(C3, "4", new StringTuple2[]{
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("3372179600339538103271349945988022057281590878984095363942286666997422318068735341921356410731048866872342085190705120335973606482705261796965921302805867402486687464498817565671630602414869908658319009361852559633642892413299578798826102373690020500698280784287903602899732371842363130786675491186765481927034947479497867265:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                            new StringTuple2("8760358328321763696208555431292826077086124252762049859683383519978601295026145187046883602155179910812803662572735996073411027946390976425893112599474627032500750406486162593908820313705403726648390884555601737640163594488411516823136829979964274602664890129139357920712122661148643142996463904160212178265964363847533415452484961528465600941167214531377002464020123544787363510400339885299974472585913942736060262730870302627851899844648009373226696514742057329667625084474434242155591087495676198334260531847346328911885145739797374169875046983176215769399554951257835823364669591933576400669027352051976293320266:-14", "1686089800169769051635674972994011028640795439492047681971143333498711159034367670960678205365524433436171042595352560167986803241352630898482960651402933701243343732249408782835815301207434954329159504680926279816821446206649789399413051186845010250349140392143951801449866185921181565393337745593382740963517473739748933633:-14"),
                    })});
                    CommonResponse commonResponse22 = new CommonResponse(C2, boostP2Res1);
                    CommonResponse commonResponse23 = new CommonResponse(C3, boostP2Res2);
                    list.add(commonResponse21);
                    list.add(commonResponse22);
                    list.add(commonResponse23);
                    return list;
                } else if (phase == 3) {
                    // 训练phase3，主动方client端收到被动方各个客户端的特征分桶信息后与本地特征进行计算并比较后找到最佳分裂特征和分裂点
                    BoostP3Res boostP3Res1 = new BoostP3Res(C3, "4", 4);
                    CommonResponse commonResponse1 = new CommonResponse(C1, boostP3Res1);
                    BoostP3Res boostP3Res2 = new BoostP3Res(null, null, 0);
                    CommonResponse commonResponse2 = new CommonResponse(C2, boostP3Res2);
                    CommonResponse commonResponse3 = new CommonResponse(C3, boostP3Res2);
                    list.add(commonResponse1);
                    list.add(commonResponse2);
                    list.add(commonResponse3);
                    return list;
                } else if (phase == 4) {
                    // 非best split所在client
                    LeftTreeInfo leftTreeInfo1 = new LeftTreeInfo(0, null);
                    // best split所在client
                    LeftTreeInfo leftTreeInfo2 = new LeftTreeInfo(1, new int[]{4, 7, 8, 6, 2});
                    CommonResponse commonResponse1 = new CommonResponse(C1, leftTreeInfo1);
                    CommonResponse commonResponse2 = new CommonResponse(C2, leftTreeInfo1);
                    CommonResponse commonResponse3 = new CommonResponse(C3, leftTreeInfo2);
                    list.add(commonResponse1);
                    list.add(commonResponse2);
                    list.add(commonResponse3);
                    return list;
                } else if (phase == 5) {
                    Map<MetricType, List<Pair<Integer, Double>>> metrics = new HashMap<>();
                    List<Pair<Integer, Double>> l1 = new ArrayList<>();
                    l1.add(new Pair<>(0, -1.7976931348623157E308));
                    l1.add(new Pair<>(1, 0.9));
                    metrics.put(MetricType.ACC, l1);
                    MetricValue trainMetric1 = new MetricValue(metrics);
                    BoostP5Res boostP5Res1 = new BoostP5Res(true, 1, trainMetric1);
                    BoostP5Res boostP5Res2 = new BoostP5Res(false, 0, null);
                    CommonResponse commonResponse1 = new CommonResponse(C1, boostP5Res1);
                    CommonResponse commonResponse2 = new CommonResponse(C2, boostP5Res2);
                    CommonResponse commonResponse3 = new CommonResponse(C3, boostP5Res2);
                    list.add(commonResponse1);
                    list.add(commonResponse2);
                    list.add(commonResponse3);
                    return list;
                }
                return null;
            }

            @Mock
            public String send(ClientInfo client, String modelToken, int phase, AlgorithmType algorithm,
                               Message data, RunningType status) {
                return "complete";
            }
        };
    }

    private static void mockInsertTrainInfo() {
        new MockUp<TrainMapper>() {
            @Mock
            public void insertTrainInfo(TrainInfo info) {
                System.out.println("插入数据库");
            }
        };
    }

    private static void mockUpdateTrainInfo() {
        new MockUp<TrainMapper>() {
            @Mock
            public void updateTrainInfo(TrainInfo trainInfo) {
                System.out.println("更新数据库 - 训练信息");
            }
        };
    }


    private void mockisContainMatchModel() {
        new MockUp<MatchMapper>() {
            @Mock
            public boolean isContainMatchModel(String token) {
                return false;
            }

        };
    }

    /**
     * @param allUids
     * @param n
     * @className InferenceTest
     * @description: 从一个数组中，随机取出不重复的n个值
     * @return: int[]
     * @author: geyan29
     * @date: 2020/11/30 15:00
     **/
    private static String[] randomUids(String[] allUids, int n) {
        String result[] = new String[n];
        int total = allUids.length;
        for (int i = 0; i < n; i++) {
            int temp = random.nextInt(total);
            result[i] = allUids[temp];
            allUids[temp] = allUids[total - 1];
            total--;
        }
        return result;
    }

    @AfterClass
    public void tearDown(){

    }
}
