/**
 * PIとの通信時、使う共通機能
 * 日付変換、メール送信なの
 */
global class NFMUtil {

    public static Integer MaxLogColumnLength = 131072;
    public static String DummyAssetProfix = '不可用：';
    public static String Authorization = 'Basic T0NNX1NGX1VTRVI6b2Ntc2ZkYzg0MDI=';

    public static final String CBPR_Auth_AWS = 'APPCODE60144b374d314ec2984182046e4ad5fb';
    public static final String APP_KEY = '47b829e07dc9512b871a677b383fb716';
    // public static final String AWS_DOMAIN = 'http://jzbase.bqbot.com:29990';
    public static String AWS_DOMAIN = '';

    public static String CLIENT_CERT_NAME = null;
    public static String NFM001_ENDPOINT = null;
    public static String NFM007_ENDPOINT = null;
    public static String NFM008_ENDPOINT = null;
    public static String NFM103_ENDPOINT = null;
    public static String NFM106_ENDPOINT = null;
    //update NFMUtil的NFM401的网站地址修改为使用FQDN。不是IP地址。
    // public static String NFM401_ENDPOINT = 'http://161.189.3.104:8088/dojtest/dojInfo/recevie';
    public static String NFM401_ENDPOINT = null;
    // public static String NFM401_ENDPOINT = 'http://192.168.0.173:8088/dojtest/dojInfo/recevie';
    //---------- insert by rentongxiao 2020-08-19
    public static String NFM402_ENDPOINT = null;
    //---------- insert by rentongxiao 2020-08-19
    public static String NFM501_ENDPOINT = null;
    public static String NFM502_ENDPOINT = null;
    //fxk 2021/9/6 Satr
    public static String NFM504_ENDPOINT = null;
    //fxk 2021/9/6 end
    // public static String NFM401_ENDPOINT = 'http://161.189.87.140:8082/doj/dojInfo/recevie';
    // LHJ 20180824 CBPR Start
    //public static String CBPR_Auth_Sap = 'Basic U0ZEQ19XU1VTRVI6cG9kMTIzNDU=';
    public static String CBPR_Auth_Sap = null;
    public static String CBPR_Auth_Spo = null;
    public static String QLM_NFM501_Point = 'application/x-www-form-urlencoded';
    public static String QLM_Token = null;
    //public static String CBPR_Auth_Spo = 'http://cbpr.chinacloudsites.cn/sfdc/token';
    //public static String CBPR_Auth_Spo = 'http://cbprproduct.chinacloudsites.cn/sfdc/token1';
    public static String CBPR_UserName_Spo = 'int1@olympus.partner.onmschina.cn';
    public static String CBPR_Password_Spo = 'Rog618571108';
    public static String appKey = '070f00bf-64f1-4720-a8d8-bbe1aa976d22';
    public static String appSecret = '67BB2BAFC8AA0BA0CABB37CBF50EC292';
    public static String NFM009_ENDPOINT = null;
    public static String NFM201_ENDPOINT = null;
    public static String NFM202_ENDPOINT = null;
    public static String NFM207_ENDPOINT = null;
    // LHJ 20180824 CBPR End
    // 智慧医疗&服务新系统通信 LY 20210916 Star
    public static String NFM621_ENDPOINT = null;
    // 智慧医疗&服务新系统通信 LY 20210916 End
    // 智慧医疗&服务新系统通信 客户接口
    public static String NFM601_ENDPOINT = null;
    // 智慧医疗&服务新系统通信 联系人接口
    public static String NFM606_ENDPOINT = null;
    // 智慧医疗&服务新系统通信 学会・活动接口
    public static String NFM622_ENDPOINT = null;
    public static String NFM701_ENDPOINT = null;
    public static String NFM702_ENDPOINT = null;
    public static String NFM703_ENDPOINT = null;

    public static String NFM115_ENDPOINT = null;

    public static String NFM112_ENDPOINT = null;


    public static String requestURILMS = null;
    public static String appSecretLMS = null;
    public static String appKeyLMS = null;
    static {
        if (isSandbox()) {
            CLIENT_CERT_NAME = 'owdc_test';
            NFM001_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM001';
            // NFM007_ENDPOINT = 'https://owdc-test.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_T&receiverParty=&receiverService=&interface=NFM007_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM007';
            //NFM007_ENDPOINT = 'http://wdp.olympus.com.cn:8089/RESTAdapter/NFM007';
            NFM007_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM007';
            NFM008_ENDPOINT = 'https://owdc-test.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_T&receiverParty=&receiverService=&interface=NFM008_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM008';
            NFM103_ENDPOINT = 'http://wdp.olympus.com.cn:8089/RESTAdapter/NFM103';
            // NFM106_ENDPOINT = 'https://owdc-test.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_T&receiverParty=&receiverService=&interface=NFM106_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM106';
            NFM106_ENDPOINT = 'http://wdp.olympus.com.cn:8089/RESTAdapter/NFM106';
            //NFM106_ENDPOINT = 'https://sfdc-ocm-test.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_T&receiverParty=&receiverService=&interface=NFM106_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM106';
            // LHJ 20180824 CBPR Start
            //NFM009_ENDPOINT = 'http://58.246.66.49:8088/RESTAdapter/SFDC002/';
            //NFM009_ENDPOINT = 'https://wstest.olympus.com.cn/RESTAdapter/SFDC002/';
            //NFM009_ENDPOINT = 'https://wdp.olympus.com.cn/RESTAdapter/SFDC002/';
            NFM009_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/SFDC002/';
            //NFM201_ENDPOINT = 'http://cbpr.chinacloudsites.cn/sfdc/Hospital';
            //NFM202_ENDPOINT = 'http://cbpr.chinacloudsites.cn/sfdc/Inquiry';
            //NFM207_ENDPOINT = 'http://cbpr.chinacloudsites.cn/sfdc/QIS';
            //NFM201_ENDPOINT = 'http://cbprproduct.chinacloudsites.cn/sfdc/Hospital';
            //NFM202_ENDPOINT = 'http://cbprproduct.chinacloudsites.cn/sfdc/Inquiry';
            //NFM207_ENDPOINT = 'http://cbprproduct.chinacloudsites.cn/sfdc/QIS';
            NFM201_ENDPOINT = 'http://cbpr.olympuschina.com/sfdc/Hospital';
            NFM202_ENDPOINT = 'http://cbpr.olympuschina.com/sfdc/Inquiry';
            NFM207_ENDPOINT = 'http://cbpr.olympuschina.com/sfdc/QIS';

            NFM401_ENDPOINT = 'http://ec2-161-189-3-104.cn-northwest-1.compute.amazonaws.com.cn:8088/dojtest/dojInfo/recevie';
            NFM402_ENDPOINT = 'http://ec2-161-189-3-104.cn-northwest-1.compute.amazonaws.com.cn:8088/dojtest/dojInfo/getDojInfoByRefNo';

            NFM501_ENDPOINT = 'http://cusdata.qianlima.com/v1/info/page/';
            NFM502_ENDPOINT = 'http://cusdata.qianlima.com/v1/info/detailHtml?url=';
            NFM504_ENDPOINT = 'http://cusdata.qianlima.com/v1/customer/albs/feedback';
            CBPR_Auth_Sap = 'Basic U0ZEQ19XU1VTRVI6cG9xMTIzNDU=';
            // LHJ 20180824 CBPR End
            //CBPR_Auth_Spo = 'http://cbpr.chinacloudsites.cn/sfdc/token';
            CBPR_Auth_Spo = 'http://cbpr.olympuschina.com/sfdc/token';

            QLM_Token = 'http://cusdata.qianlima.com/v1/token';
            

            // 智慧医疗&服务新系统通信 客户接口
            NFM601_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM601';
            // 智慧医疗&服务新系统通信 联系人接口
            NFM606_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM606';
            // 智慧医疗&服务新系统通信 用户接口
            NFM621_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM621';
            NFM622_ENDPOINT = 'http://test-platform.olympuschina.com/prod-api/api/sso/sfdc_activitydata';
            NFM701_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM701';
            NFM702_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM702';
            NFM703_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM703';
            
            NFM112_ENDPOINT = 'http://wdp.olympus.com.cn:8089/RESTAdapter/NFM112';

            NFM115_ENDPOINT = 'https://wdp.olympus.com.cn:44301/RESTAdapter/NFM115';
            // 新服务系统 测试环境
            AWS_DOMAIN = 'https://olympus.bqbot.com';
            // 新服务系统 本地环境（临时）
            // AWS_DOMAIN = 'http://114.249.236.98:29990';
            // AWS_DOMAIN = 'http://jzbase.bqbot.com:29990';
            // AWS_DOMAIN = 'http://114.249.238.243:29990';
            

            requestURILMS = '/v1/uc/user/syncOlympusUnit';
            appSecretLMS = 'CAE1D68BE3EB4F7AB5FE97EBDD11B83E';
            appKeyLMS = '39111FC57691491190C1D137A1EE3962';
        } else {
            CLIENT_CERT_NAME = 'sfdc_ocm';
            NFM001_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM001';
            //NFM007_ENDPOINT = 'https://owdc.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_P&receiverParty=&receiverService=&interface=NFM007_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM007';
            NFM007_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM007';
            NFM008_ENDPOINT = 'https://owdc.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_P&receiverParty=&receiverService=&interface=NFM008_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM008';
            //NFM103_ENDPOINT = 'https://owdc.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_P&receiverParty=&receiverService=&interface=NFM103_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM103';
            NFM103_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM103';
            //NFM106_ENDPOINT = 'https://owdc.olympus.co.jp/XISOAPAdapter/MessageServlet?senderParty=&senderService=OCM_SFDC_P&receiverParty=&receiverService=&interface=NFM106_Sync_BC2GPI&interfaceNamespace=http%3A%2F%2Folympus.co.jp%2Fgpi%2FNFM106';
            NFM106_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM106';
            // LHJ 20180824 CBPR Start
            NFM009_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/SFDC002/';
            //NFM201_ENDPOINT = 'http://cbprproduct.chinacloudsites.cn/sfdc/Hospital';
            //NFM202_ENDPOINT = 'http://cbprproduct.chinacloudsites.cn/sfdc/Inquiry';
            //NFM207_ENDPOINT = 'http://cbprproduct.chinacloudsites.cn/sfdc/QIS';
            NFM201_ENDPOINT = 'http://cbprproduct.olympuschina.com/sfdc/Hospital';
            NFM202_ENDPOINT = 'http://cbprproduct.olympuschina.com/sfdc/Inquiry';
            NFM207_ENDPOINT = 'http://cbprproduct.olympuschina.com/sfdc/QIS';

            NFM401_ENDPOINT = 'http://ec2-161-189-3-104.cn-northwest-1.compute.amazonaws.com.cn:8082/doj/dojInfo/recevie';
            NFM402_ENDPOINT = 'http://ec2-161-189-3-104.cn-northwest-1.compute.amazonaws.com.cn:8082/doj/dojInfo/getDojInfoByRefNo';

            NFM501_ENDPOINT = 'http://cusdata.qianlima.com/v1/info/page/';
            NFM502_ENDPOINT = 'http://cusdata.qianlima.com/v1/info/detailHtml?url=';
            NFM504_ENDPOINT = 'http://cusdata.qianlima.com/v1/customer/albs/feedback';
            CBPR_Auth_Sap = 'Basic U0ZEQ19XU1VTRVI6cG9wMTIzNDU=';
            //CBPR_Auth_Spo = 'http://cbprproduct.chinacloudsites.cn/sfdc/token';
            CBPR_Auth_Spo = 'http://cbprproduct.olympuschina.com/sfdc/token';
            // LHJ 20180824 CBPR End
            QLM_Token = 'http://cusdata.qianlima.com/v1/token';

            // 智慧医疗&服务新系统通信 客户接口
            NFM601_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM601';
            // 智慧医疗&服务新系统通信 联系人接口
            NFM606_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM606';
            // 智慧医疗&服务新系统通信 用户接口
            NFM621_ENDPOINT = 'https://wdp.olympus.com.cn:44302/RESTAdapter/NFM621';
            NFM622_ENDPOINT = 'https://api-platform.olympuschina.com/prod-api/api/sso/sfdc_activitydata';

            // 新服务系统
            AWS_DOMAIN = 'https://svc-elb.olympuschina.com';

            requestURILMS = '/v1/uc/user/syncOlympusUnit';
            appSecretLMS = '569117ED8E574BF3A6E4247C1AF8118A';
            appKeyLMS = 'B70889DEF6E647EC8A542E3C46925F93';
        }
    }

    // 受信用
    global class Monitoring {
        webservice String Tag;
        webservice String Sender;
        webservice String Receiver;
        webservice String MessageType;
        webservice String MessageGroupNumber;
        webservice String NumberOfRecord;
        webservice String TransmissionDateTime;
        webservice String Text;
    }
    // NFM622使用
    global class MonitoringToOnline {
        webservice String Tag;
        webservice String Sender;
        webservice String Receiver;
        webservice String MessageType;
        webservice String MessageGroupNumber;
        webservice String NumberOfRecord;
        webservice String TransmissionDateTime;
        webservice String Text;
        webservice String username;
        webservice String password;
    }
    // NFM601、NFM606、NFM621使用
    global class MonitoringToComPlat {
        webservice String Tag;
        webservice String Sender;
        webservice String Receiver;
        webservice String MessageType;
        webservice String MessageGroupNumber;
        webservice String NumberOfRecord;
        webservice String TransmissionDateTime;
        webservice String Text;
        webservice String API_RANDOM_STR;
        webservice String API_TIME;
        webservice String API_TOKEN;
        webservice String sign;
        webservice String timestamp;
        webservice String appKey;
    }

    /**
     * @return yyyyMMdd の日付文字列
     */
    public static String formatDate2Str(Date dt) {
        String rtn = null;
        if (dt == null) {
            return rtn;
        }
        rtn = String.valueOf(dt);
        rtn = rtn.replaceAll('-', '');
        if (rtn >= '40001231') {
            rtn = '99991231';
        } else if (rtn < '19000101') {
            rtn = '19000101';
        }
        return rtn;
    }

    /**
     * @return yyyyMMdd の日付文字列
     */
    public static String formatDate2StrDateTime(Date dt) {
        String rtn = null;
        if (dt == null) {
            return rtn;
        }
        rtn = String.valueOf(dt);
        rtn = rtn.replaceAll('-', '');
        if (rtn >= '40001231') {
            rtn = '99991231';
        } else if (rtn < '19000101') {
            rtn = '19000101';
        }
        return rtn + '000000';
    }

    /**
     * [formatDate2StrDateNewTime description]
     * @param  dt [日期]
     * @return    [description]
     * 拼接日期/时间，参数日期（年月日）+ 当前时间（时分秒）
     */
    public static String formatDate2StrDateNewTime(Date dt) {
        String rtn = null;
        if (dt == null) {
            return rtn;
        }
        rtn = String.valueOf(dt);
        rtn = rtn.replaceAll('-', '');
        if (rtn >= '40001231') {
            rtn = '99991231';
        } else if (rtn < '19000101') {
            rtn = '19000101';
        }

        String phourMinuteSecond = String.valueOf(DateTime.now());
        if(phourMinuteSecond.length() >= 19){
            phourMinuteSecond = phourMinuteSecond.subString(10,19).replaceall(':', '');
        }
        return rtn + phourMinuteSecond;
    }


    /**
     * @return yyyyMMddHHmmss の日付文字列
     */
    public static String formatDateTime2Str(Datetime dt) {
        String rtn = null;
        if (dt == null) {
            return rtn;
        }
        rtn = String.valueOf(dt);
        rtn = rtn.replaceAll('-', '').replaceall(' ', '').replaceall(':', '');
        if (rtn >= '40001231000000') {
            rtn = '99991231000000';
        } else if (rtn < '19000101000000') {
            rtn = '19000101000000';
        }
        return rtn;
    }

    // LHJ Start
    /**
     * @return yyyyMMdd の日付文字列
     */
    public static String formatDate2StrSpo(Date dt) {
        String rtn = null;
        if (dt == null) {
            rtn = '2999-12-31';
        } else {
            rtn = String.valueOf(dt);
        }
        return rtn;
    }

    // LHJ Start
    /**
     * @return yyyy/MM/dd の日付文字列
     */
    public static String formatDateTime2StrSprit(DateTime dt) {
        String rtn = null;
        if (dt == null) {
            rtn = '';
        } else {
            String pDate = formatDateTime2Str(dt);
            rtn = Integer.valueOf(pDate.substring(0, 4)) + '/' +
                Integer.valueOf(pDate.substring(4, 6)) + '/' +
                Integer.valueOf(pDate.substring(6, 8));
        }
        return rtn;
    }

    /**
     * add       wangweipeng       2022/02/11
     * [formatDateTime2StrDateTime description]
     * @param  dt [日期/时间]
     * @return    [字符串]
     *
     * 此方法用于新建数据时，把 日期/时间 转换成字符串类型，并把 秒 去掉
     */
    public static String formatDateTime2StrDateTime(DateTime dt){
        String rtn = null;
        if (dt == null) {
            return rtn;
        }
        rtn = String.valueOf(dt);
        rtn = rtn.replaceAll('-', '/');
        if (rtn >= '40001231000000') {
            rtn = '99991231000000';
        } else if (rtn < '19000101000000') {
            rtn = '19000101000000';
        }
        //去掉 秒
        rtn = rtn.substring(0,rtn.length()-3);
        return rtn;
    }

    // LHJ End

    public static Date parseStr2DateTimeDate(String pDateTime) {
        if (pDateTime == null || pDateTime.length() != 14) {
            return null;
        }
        return parseStr2Date(pDateTime.substring(0, 8));
    }

    /**
     * add    wangweipeng           2022/02/15
     * [parseStr2DateTime description]
     * @param  pDate [日期（不包括时间）]
     * @return           [description]
     *
     * 拼接日期/时间，其中日期为真实日期，时间为当前时间
     
     */
    public static Datetime parseStr3DateTime(String pDate) {
        if (String.isBlank(pDate)) {
            return null;
        }
        String phourMinuteSecond = String.valueOf(DateTime.now());
        if(phourMinuteSecond.length() >= 19){
            phourMinuteSecond = phourMinuteSecond.subString(10,19).replaceall(':', '');
        }
        return parseStr2DateTime(pDate.substring(0, 8), phourMinuteSecond);
    }

    public static Datetime parseStr2DateTime(String pDateTime) {
        if (pDateTime == null || pDateTime.length() != 14) {
            return null;
        }
        return parseStr2DateTime(pDateTime.substring(0, 8), pDateTime.substring(8, 14));
    }

    public static Datetime parseStr2DateTime(String pDate, String pTime) {
        Datetime rtn = null;
        try {
            if (pDate == null || pDate.length() != 8) {
                return rtn;
            } else if (pDate > '40001231') {
                pDate = '40001231';
            } else if (pDate < '19000101') {
                pDate = '19000101';
            }
            if (pDate == '19000101') {
                return null;
            }
            rtn = Datetime.newinstance(
                Integer.valueOf(pDate.substring(0, 4)),
                Integer.valueOf(pDate.substring(4, 6)),
                Integer.valueOf(pDate.substring(6, 8)),
                Integer.valueOf(pTime.substring(0, 2)),
                Integer.valueOf(pTime.substring(2, 4)),
                Integer.valueOf(pTime.substring(4, 6))
            );
        } catch (Exception ex) {
            System.debug(Logginglevel.ERROR, 'NFMUtil#parseStr2DateTime(' + pDate + ', ' + pTime + ')' + ex.getMessage());
        }
        return rtn;
    }
    /**
     * @param pStr yyyyMMdd の日付文字列
     */
    public static Date parseStr2Date(String pStr) {
        return parseStr2Date(pStr, true);
    }
    /**
     * @param pStr         yyyyMMdd の日付文字列
     * @param changeToNull 19000101以下の場合 null に変換するかどうか
     */
    public static Date parseStr2Date(String pStr, boolean changeToNull) {
        Date rtn = null;
        try {
            if (pStr == null || pStr.length() != 8 || pStr == '00000000') {
                return rtn;
            } else if (pStr > '40001231') {
                pStr = '40001231';
            } else if (pStr < '19000101') {
                pStr = '19000101';
            }
            if (pStr == '19000101' && changeToNull) {
                return null;
            }
            rtn = Date.newinstance(
                Integer.valueOf(pStr.substring(0, 4)),
                Integer.valueOf(pStr.substring(4, 6)),
                Integer.valueOf(pStr.substring(6, 8))
            );
        } catch (Exception ex) {
            System.debug(Logginglevel.ERROR, 'NFMUtil#parseStr2Date(' + pStr + ')' + ex.getMessage());
        }
        return rtn;
    }

    /**
     * @param pStr         yyyyMMdd の日付文字列
     * @param changeToNull 19000101以下の場合 null に変換するかどうか
     */
    public static Date parseDateTimeStr2Date(String pStr) {
        if (pStr == null || pStr.length() < 8) {
            return null;
        } else {
            pStr = pStr.replace('-', '').replace('/', '');
            String dateStr = pStr.substring(0, 8);
            return parseStr2Date(dateStr, true);
        }
    }



    /**
     * もしkeyがmapに存在しない場合、keyをそのまま戻る
     */
    public static String getMapValue(Map < String, String > transferMap, String col, String key, BatchIF_Log__c iflog) {
        String rtn = key;
        if (transferMap == null) {
            return rtn;
        }
        if (key == null) {
            return null;
        }
        if (col == null) {
            col = '';
        }
        rtn = transferMap.get(col + key);
        if (rtn == null) {
            iflog.ErrorLog__c += 'Warning! Please check [' + col + '] can not transfer key [' + key + ']\n';
            rtn = key;
        }
        return rtn;
    }

    /**
     * LMS使用(NFM601使用)
     * @return [description]
     */
    public static String getSignMD5(){
        
        String signText = appSecretLMS + '|' + requestURILMS + '|' + appSecretLMS;
        String signMD5 = EncodingUtil.convertToHex(Crypto.generateDigest('MD5', Blob.valueOf(signText))).toUpperCase();
        String result = signMD5;
        return signMD5;
    }

    public static String randomUUID(Integer length) {

        String result = '';
        for (Integer i = 0; i < length; i++) {

            Integer ran = (Math.random() * 16).intValue();
            if (ran == 10) {
                result += 'A';
            } else if (ran == 11) {
                result += 'B';
            } else if (ran == 12) {
                result += 'C';
            } else if (ran == 13) {
                result += 'D';
            } else if (ran == 14) {
                result += 'E';
            } else if (ran == 15) {
                result += 'F';
            } else {
                result += ran.format();
            }

        }
        return result;
    }

    public static String getToken(String randomstr, long timestamp) {
        if (randomstr == null) {
            randomstr = randomUUID(16);
        }
        System.debug('-------------------randomstr:' + randomstr);
        System.debug('-------------------timestamp:' + timestamp);
        String str = 'appkey=' + APP_KEY + '&timestamp=' + timestamp + '&random_str=' + randomstr + '&key=' + APP_KEY;

        String result = EncodingUtil.convertToHex(Crypto.generateDigest('MD5', Blob.valueOf(str)));
        System.debug('-------------------result:' + result);
        return result;

    }

    /**
     * 先頭の指定文字をtrim
     *
     * @param trimChar 指定したtrim文字
     */
    public static String trimLeft(String orgStr, String trimChar) {
        String rtn = orgStr;
        if (orgStr == null) {
            return rtn;
        }
        if (trimChar == null) {
            return null;
        }
        rtn = orgStr.replaceAll('^' + trimChar + '+(?!$)', '');
        return rtn;
    }

    public static Boolean isSandbox() {
        //return URL.getSalesforceBaseUrl().getHost().left(2).equalsignorecase('cs') || URL.getSalesforceBaseUrl().toExternalForm().CONTAINS('.cs');
        return [SELECT IsSandbox FROM Organization LIMIT 1].IsSandbox;
    }

    public static BatchIF_Log__c makeRowData(NFMUtil.Monitoring Monitoring, String NFMType, Object NFMData) {
        BatchIF_Log__c rowData = new BatchIF_Log__c();
        rowData.Type__c = NFMType;
        rowData.MessageGroupNumber__c = Monitoring.MessageGroupNumber;
        rowData.TransmissionDateTime__c = Monitoring.TransmissionDateTime;
        rowData.RowDataFlg__c = true;
        rowData.Log__c = '';
        rowData.ErrorLog__c = '';
        String rowDataStr = JSON.serialize(NFMData);
        if (rowDataStr.length() > 0) {
            Integer splitIdx = 1;
            while (rowDataStr.length() > 0) {
                if (splitIdx == 1) {
                    rowData.put('Log__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
                } else if (splitIdx == 13) {
                    rowData.ErrorLog__c = rowDataStr;
                    break;
                } else {
                    rowData.put('Log' + splitIdx + '__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
                }
                splitIdx++;
                rowDataStr = rowDataStr.substring((rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length()));
            }
        }
        return rowData;
    }

    // public static BatchIF_Log__c makeRowDataToOnline(NFMUtil.MonitoringToOnline Monitoring, String NFMType, Object NFMData) {
    //     BatchIF_Log__c rowData = new BatchIF_Log__c();
    //     rowData.Type__c = NFMType;
    //     rowData.MessageGroupNumber__c = Monitoring.MessageGroupNumber;
    //     rowData.TransmissionDateTime__c = Monitoring.TransmissionDateTime;
    //     rowData.RowDataFlg__c = true;
    //     rowData.Log__c = '';
    //     rowData.ErrorLog__c = '';
    //     String rowDataStr = JSON.serialize(NFMData);
    //     if (rowDataStr.length() > 0) {
    //         Integer splitIdx = 1;
    //         while (rowDataStr.length() > 0) {
    //             if (splitIdx == 1) {
    //                 rowData.put('Log__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
    //             } else if (splitIdx == 13) {
    //                 rowData.ErrorLog__c = rowDataStr;
    //                 break;
    //             } else {
    //                 rowData.put('Log' + splitIdx + '__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
    //             }
    //             splitIdx++;
    //             rowDataStr = rowDataStr.substring((rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length()));
    //         }
    //     }
    //     return rowData;
    // }
    public static BatchIF_Log__c makeRowData(BatchIF_Log__c iflog, String NFMType, Object NFMData) {
        // TransmissionDateTimeの設定
        Datetime nowDT = Datetime.now();
        String nowStr = nowDT.format('yyyyMMddHHmm');
        BatchIF_Log__c rowData = new BatchIF_Log__c();
        rowData.Type__c = NFMType;
        rowData.MessageGroupNumber__c = iflog.Name;
        rowData.TransmissionDateTime__c = nowStr;
        rowData.RowDataFlg__c = true;
        rowData.Log__c = '';
        rowData.ErrorLog__c = '';
        String rowDataStr = JSON.serialize(NFMData);
        if (rowDataStr.length() > 0) {
            Integer splitIdx = 1;
            while (rowDataStr.length() > 0) {
                if (splitIdx == 1) {
                    rowData.put('Log__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
                } else if (splitIdx == 13) {
                    rowData.ErrorLog__c = rowDataStr;
                    break;
                } else {
                    rowData.put('Log' + splitIdx + '__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
                }
                splitIdx++;
                rowDataStr = rowDataStr.substring((rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length()));
            }
        }
        return rowData;
    }

    public static BatchIF_Log__c saveRowData(NFMUtil.Monitoring Monitoring, String NFMType, Object NFMData) {
        BatchIF_Log__c rowData = makeRowData(Monitoring, NFMType, NFMData);
        insert rowData;
        return rowData;
    }
    public static String getRowDataStr(BatchIF_Log__c rowData) {
        String rowDataStr = rowData.Log__c;
        Integer splitIdx = 2;
        while (rowData.get('Log' + splitIdx + '__c') != null && String.isBlank('' + rowData.get('Log' + splitIdx + '__c')) == false) {
            rowDataStr += rowData.get('Log' + splitIdx + '__c');
            splitIdx++;
            if (splitIdx == 13) break;
        }
        if (String.isBlank(rowData.ErrorLog__c) == false) {
            rowDataStr += rowData.ErrorLog__c;
        }
        return rowDataStr;
    }

    // 20180823 LHJ C-BPR Spo接口认证 Start

    public class Token_Response {
        public String expires_in;
        public String access_token;
    }


    public class AWS_Response {
        public Integer code;
        public String msg;
        public String data;
    }

    public static String sendToSpoRet(String rowDataStr, String endpoint) {
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        // 获取token
        req.setEndpoint(CBPR_Auth_Spo);
        req.setMethod('POST');
        req.setHeader('grant_type', 'password');
        req.setHeader('username', CBPR_UserName_Spo);
        req.setHeader('password', CBPR_Password_Spo);
        req.setBody('');
        res = http.send(req);
        resb = res.getBody();

        Token_Response tr = (Token_Response) JSON.deserialize(resb, Token_Response.class);
        // 发送接口
        Http http2 = new Http();
        HttpRequest req2 = new HttpRequest();
        HTTPResponse res2;
        String resb2;

        req2.setTimeout(110000);
        req2.setEndpoint(endpoint);
        req2.setMethod('POST');
        req2.setHeader('access_token', tr.access_token);
        req2.setHeader('Content-Type', 'application/json');
        req2.setBody(rowDataStr);
        res2 = http2.send(req2);
        resb2 = res2.getStatus();

        return resb2;
    }

    /*
        send to AWS
    */
    public static String sendToAWS(String rowDataStr, String endpoint) {

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;
        system.debug('sendToAWS--->rowDataStr----->'+rowDataStr);
        // List<GeDatas> GeDataList = (List<GeDatas>) JSON.deserialize(rowDataStr, List<GeData>.class);
        req.setTimeout(120000);
        req.setEndpoint(AWS_DOMAIN + endpoint);
        req.setMethod('POST');
        //req.setHeader('Authorization', CBPR_Auth_AWS);
        String randomstr = randomUUID(16);
        long timestamp = DateTime.now().getTime();
        req.setHeader('Content-Type', 'application/json');
        req.setHeader('API-RANDOM-STR', randomstr);
        req.setHeader('API-TIME', timestamp + '');
        req.setHeader('API-TOKEN', getToken(randomstr, timestamp));
        req.setBody(rowDataStr);
        system.debug('req--->'+req);
        //return '';
        res = http.send(req);
        // resb = res.getBody();
        resb = res.getStatus();
        //AWS_Response tr = (AWS_Response) JSON.deserialize(resb, AWS_Response.class);
        return resb;

    }

    public static void sendToSpo(String rowDataStr, String endpoint) {

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        // 获取token
        req.setEndpoint(CBPR_Auth_Spo);
        req.setMethod('POST');
        req.setHeader('grant_type', 'password');
        req.setHeader('username', CBPR_UserName_Spo);
        req.setHeader('password', CBPR_Password_Spo);
        req.setBody('');
        res = http.send(req);
        resb = res.getBody();

        Token_Response tr = (Token_Response) JSON.deserialize(resb, Token_Response.class);
        // 发送接口
        Http http2 = new Http();
        HttpRequest req2 = new HttpRequest();
        HTTPResponse res2;
        String resb2;

        req2.setTimeout(120000);
        req2.setEndpoint(endpoint);
        req2.setMethod('POST');
        req2.setHeader('access_token', tr.access_token);
        req2.setHeader('Content-Type', 'application/json');
        req2.setBody(rowDataStr);
        res2 = http2.send(req2);
        resb2 = res2.getStatus();

    }

    // 20180823 LHJ C-BPR Sap接口认证 Start
    public static void sendToSap(String rowDataStr, String endpoint) {

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        req.setTimeout(120000);
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Authorization', CBPR_Auth_Sap);
        req.setBody(rowDataStr);

        res = http.send(req);
        resb = res.getBody();
    }

    // 20180823 LHJ C-BPR Sap接口认证 Start
    public static String sendToETQ(String rowDataStr, String endpoint) {

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        req.setTimeout(120000);
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(rowDataStr);

        res = http.send(req);
        resb = res.getStatus();
        system.debug('resb:' + resb);
        return resb;
    }

    public static String sendToSapRet(String rowDataStr, String endpoint) {

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        req.setTimeout(120000);
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Authorization', CBPR_Auth_Sap);
        req.setBody(rowDataStr);

        res = http.send(req);
        resb = res.getStatus();
        system.debug('resb:' + resb);
        return resb;
    }
    // WLIG-BXQBH6 额外接收reponse 的body start
    public static response sendToSapStatusAndBody(String rowDataStr, String endpoint) {

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        req.setTimeout(120000);
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Authorization', CBPR_Auth_Sap);
        req.setBody(rowDataStr);

        res = http.send(req);
        string ress = res.getStatus();
        resb = res.getBody();
        system.debug('ress:' + ress);
        return new response(ress, resb);
    }

    public class response {
        public string status;
        public string responseBody;
        public response(string status, string responseBody) {
            this.status = status;
            this.responseBody = responseBody;
        }
    }
    // WLIG-BXQBH6 end
    //---------- insert by rentongxaio   2020-08-19 Start
    public static String getETQData(String rowDataStr, String endpoint) {

        HttpRequest req = new HttpRequest();
        //endPoint 就是请求路径
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        //请求参数
        req.setBody(rowDataStr);

        Http http = new Http();
        HTTPResponse res = http.send(req);

        String responseBody = res.getBody();
        return responseBody;
    }

    //---------- insert by rentongxiao 2020-08-19 End


    //返回格式: hh:ss:mm
    //insert by rentongxiao 2020-10-12 start
    public static Time parseStr2Time(String timeStr) {
        if (timeStr.length() != 6) {
            return null;
        }
        return Time.newInstance(
            Integer.valueOf(timeStr.substring(0, 2)),
            Integer.valueOf(timeStr.substring(2, 4)),
            Integer.valueOf(timeStr.substring(4, 6)),
            0);
    }
    //insert by rentongxiao 2020-10-12 end

    //千里马
    //接口1，获取token
    public class Body {
        public String msg;
        public String access_token;
        public String code;
    }
    public class Body502 {
        public String msg;
        public String data1;
        public String code;
    }

    public static response receiveToken() {
        //1、 获取token:
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        String content = 'appKey=' + EncodingUtil.urlEncode(appKey, 'UTF-8') +
            '&appSecret=' + EncodingUtil.urlEncode(appSecret, 'UTF-8');
        //请求路径
        req.setEndpoint(QLM_Token);
        req.setHeader('Content-Type', QLM_NFM501_Point);
        req.setMethod('POST');
        //请求参数
        req.setBody(content);
        //两个code分别为：
        //1.http：code和状态
        //2.
        HTTPResponse response = http.send(req);
        string ress = response.getStatus();
        System.debug('response:' + response);
        System.debug('Status:' + ress);
        //`1.http:code和状态
        //如果状态不通过，则为他其状态及token = null返回

        if (string.isBlank(ress) || !ress.replace('o', 'O').replace('k', 'K').equals('OK')) {
            return new response(ress, null);
        }

        String responseBodyToken = response.getBody();
        System.debug('Body:' + responseBodyToken);
        Body BodyToken = (Body) JSON.deserializeStrict(responseBodyToken, Body.class);
        System.debug('======1=====' + BodyToken.code);
        //如果解析时code不为0，则将其错误信息及token = null返回
        if (String.isBlank(BodyToken.code) || !BodyToken.code.equals('0')) {
            System.debug('======12=====' + BodyToken.code);
            return new response(BodyToken.msg, null);
        }
        //正常执行
        String token = BodyToken.access_token;
        return new response(ress, token);
    }

    //接口2，获取接口中的数据   和  接口3，获取页面
    public static response getQLMData(String endpoint, String token) {
        //2、获取招标信息：记得使用1中获取的token
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setHeader('Content-Type', QLM_NFM501_Point);
        req.setHeader('open-authorization', 'Bearer' + token);
        req.setTimeout(120000);
        req.setEndpoint(endpoint);
        req.setMethod('GET');

        HTTPResponse response = http.send(req);
        String ress = response.getStatus();
        System.debug('response:' + response);
        //http：状态和code
        //如果状态不通过 ， 则将状态及空的的数据 ， 返回
        if (string.isBlank(ress) || !ress.replace('o', 'O').replace('k', 'K').equals('OK')) {
            return new response(ress, null);
        }
        System.debug('=====2======' + response.getBody());
        //正常执行
        return new response(ress, response.getBody());
    }

    //接口3，获取其他附件
    public static response503 getFileData(String token503, String endpoint) {
        //4、获取网页：记得使用1中获取的token，记得EndPoint 使用2中获取的网页
        try {
            Http http503 = new Http();
            HttpRequest req503 = new HttpRequest();
            req503.setHeader('open-authorization', 'Bearer' + token503);
            req503.setTimeout(120000);
            req503.setEndpoint(endpoint);
            req503.setMethod('GET');

            HTTPResponse NFM503response = http503.send(req503);
            System.debug('NFM503response:' + NFM503response);
            System.debug('12345678' + NFM503response.getHeader('Content-Disposition'));
            String ress503 = NFM503response.getStatus();
            if (string.isBlank(ress503) || !ress503.replace('o', 'O').replace('k', 'K').equals('OK')) {
                return new response503(ress503, null, null);
            }

            string str = NFM503response.getHeader('Content-Disposition');
            string fileName = str.replaceall('filename=', '').replaceall('attachment;', '');
            fileName = EncodingUtil.urlDecode(fileName, 'utf-8');
            Blob responseBody503 = NFM503response.getBodyAsBlob();
            System.debug('=====2======' + NFM503response.getBodyAsBlob());
            return new response503(ress503, responseBody503, fileName);
        } catch (Exception ex) {
            return new response503('', Blob.valueOf('文件大小超过12M'), '文件大小超过12M');
        }
    }

    public class response503 {
        public string status;
        public Blob responseBody;
        public String Name;
        public response503(string status, Blob responseBody, String Name) {
            this.status = status;
            this.responseBody = responseBody;
            this.Name = Name;
        }
    }

    //接口4，发送要删除项目的信息Id。。。2021/9/2,逻辑删除新加接口 fxk
    public static String sendTenInfo(String token504, String jsonStr, String endpoint) {
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://cusdata.qianlima.com/test/v1/customer/albs/feedback');
        req.setHeader('open-authorization', 'Bearer' + token504);
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        req.setMethod('POST');
        req.setBody(jsonStr);

        HTTPResponse response = http.send(req);
        string ress = response.getStatus();
        // if (string.isBlank(ress) || !ress.replace('o', 'O').replace('k', 'K').equals('OK')) {
        //     return new response(ress, null);
        // }
        System.debug('Body ' + response.getBody());
        System.debug('Status ' + response.getStatus());
        System.debug('Status code ' + response.getStatusCode());
        return ress;
    }


    // 最大值为3，用来作为判断错误的条件（重发三次）
    public static Integer batch_retry_max_cnt = Integer.valueOf(System.Label.batch_retry_max_cnt);
    public static void againSendRequest(BatchIF_Log__c iflog, String count, BatchIF_Log__c rowData, String errorStr) {
        //判断rowdata中数据获取成功与否，如果失败重发三次，如果大于三次则手动操作
        System.debug('----====---9-------');
        Integer rowDataStr = Integer.valueOf(rowData.get(count));
        if (rowDataStr == null) {
            rowDataStr = 0;
        }
        if (rowDataStr < batch_retry_max_cnt) {
            rowDataStr++;
            LogAutoSendSchedule.assignOneMinute();
        }
        if (rowDataStr >= batch_retry_max_cnt) {
            iflog.ErrorLog__c += errorStr;
            rowData.ErrorLog__c += errorStr;
        }
        upsert rowData;
        upsert iflog;
        rowData.put(count, rowDataStr);
    }

    //因log存入数据有限，所以防止数据太多
    public static String QLMgetRowDataStr(BatchIF_Log__c rowData) {
        String QLMDataStr = rowData.Log__c;
        Integer splitIdx = 2;
        while (rowData.get('Log' + splitIdx + '__c') != null && String.isBlank('' + rowData.get('Log' + splitIdx + '__c')) == false) {
            QLMDataStr += rowData.get('Log' + splitIdx + '__c');
            splitIdx++;
            if (splitIdx == 13) break;
        }
        return QLMDataStr;
    }

    //创建RowDataFlg类型的日志
    // public static BatchIF_Log__c QLMsaveRowData( String NFMType, Object NFMData) {
    //     BatchIF_Log__c rowData = QLMmakeRowData( NFMType, NFMData);
    //     insert rowData;
    //     return  rowData;
    // }

    public static BatchIF_Log__c QLMmakeRowData(String response, BatchIF_Log__c rowData) {

        rowData.Log__c = '';
        rowData.ErrorLog__c = '';
        String rowDataStr = response;
        Integer MaxLogColumnLength = 131072;
        if (rowDataStr.length() > 0) {
            Integer splitIdx = 1;
            while (rowDataStr.length() > 0) {
                if (splitIdx == 1) {
                    rowData.put('Log__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
                } else if (splitIdx == 13) {
                    rowData.ErrorLog__c = rowDataStr;
                    break;
                } else {
                    rowData.put('Log' + splitIdx + '__c', rowDataStr.substring(0, (rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length())));
                }
                splitIdx++;
                rowDataStr = rowDataStr.substring((rowDataStr.length() > MaxLogColumnLength ? MaxLogColumnLength : rowDataStr.length()));
            }
        }
        return rowData;
    }
    public static BatchIF_Log__c LogAutoSend(BatchIF_Log__c rowDataSFDC, Exception ex, String status) {
        Integer batch_retry_max_cnt = Integer.valueOf(System.Label.batch_retry_max_cnt);
        if (rowDataSFDC.retry_cnt__c == null) rowDataSFDC.retry_cnt__c = 0;
        if (rowDataSFDC.retry_cnt__c < batch_retry_max_cnt) {
            rowDataSFDC.retry_cnt__c++;
            LogAutoSendSchedule.assignOneMinute();
        }
        if (rowDataSFDC.retry_cnt__c >= batch_retry_max_cnt) {
            if (ex == null) {
                rowDataSFDC.ErrorLog__c = status + '\n错误次数已经超过自动送信设定的最大次数，请手动送信';
            } else {
                rowDataSFDC.ErrorLog__c = ex.getMessage() + '\n' + ex.getStackTraceString() + '\n' + rowDataSFDC.ErrorLog__c + '错误次数已经超过自动送信设定的最大次数，请手动送信';
            }

        }
        return rowDataSFDC;
    }
    // https://oly.ngrok.kunchuangtech.net/api/sso/sfdc_activitydata
    //发送给共通平台 精琢技术 thh 2021-09-22 start
    public static String sendToComPlat(String rowDataStr, String endpoint) {
        Http http = new Http();
        HttpRequest req = new HttpRequest();
        HTTPResponse res;
        String resb;

        req.setTimeout(120000);
        req.setEndpoint(endpoint);
        req.setMethod('POST');
        req.setHeader('Content-Type', 'application/json');
        req.setBody(rowDataStr);

        res = http.send(req);
        resb = res.getStatus();
        system.debug('resb:' + resb);
        return resb;
    }

    
    //发送给共通平台 精琢技术 thh 2021-09-22 end
    
    public static Integer ControllerUtil() {
        Integer i = 0;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        i++;
        return i;
    }
}