Untitled

mail@pastecode.io avatar
unknown
javascript
2 years ago
107 kB
2
Indexable
Never
var ekycSDK = (function () {
    var __wrapper;
    var __options;

    var __sessionPlan;
    var __uploadType;
    var __allowFullResults;
    var __pc;

    var __dc;

    // Liveness functions

    var __webcam;

    var __guideBox;
    var __guideTitle;
    var __guideIcons = [];
    var __lvns_step = 1;
    var __successIcon;
    var __warningIcon;    

    const LIVENESS_MESSAGES = {
        'TurnLeft': 'Quay trái',
        'TurnRight': 'Quay phải',
        'TurnUp': 'Ngửa đầu',
        'TurnDown': 'Cúi đầu',
        'HoldSteady2Second': 'Nhìn thẳng trong 2 giây',
        'EyeBlink': 'Nháy mắt',
        'ShakeHead': 'Lắc đầu sang trái hoặc phải',
        'NodeHead': 'Gật đầu',
        'Success': 'success',
        'Connecting': 'Đang kết nối...',
        'Initializing': 'Đang khởi tạo...',
        'Processing': 'Đang xác thực...',
        'ConnectionFailed': 'Kết nối thất bại'
    };

    var __createPeerConnection = function () {
        __pc = new RTCPeerConnection({
            sdpSemantics: 'unified-plan',
            iceTransportPolicy: 'relay',
            iceServers: [
                {
                    urls: ['turn:27.71.226.88:64001?transport=tcp'],
                    credential: 'kalapa123456',
                    username: 'kalapa'
                }
            ]
        });

        __pc.addEventListener('icegatheringstatechange', function() {
            console.log(__pc.iceGatheringState)
        }, false);

        __pc.addEventListener('iceconnectionstatechange', function () {
            if (['disconnected', 'failed'].includes(__pc.iceGatheringState)) {
                __stop();
                console.log(LIVENESS_MESSAGES['ConnectionFailed']);

            }
        }, false);
    };

    var __createDataChannel = function () {
        __dc = __pc.createDataChannel('chat', {ordered: true});
    };

    var __handleMessageEvent = function () {
        __dc.onmessage = function (e) {
            var data = e.data.split("&&")[1].replaceAll("'", '"');
            data = JSON.parse(data);
            console.log(data);
            var message = '';
            if (data.status === 3) {
                __stop();
                message = 'Không đạt, vui lòng thử lại.';
                __showError(message, liveness, true);
            } else if (data.status === 2) {
                __stop();
                __warningIcon.css('display', 'block');                
                message = 'Quá thời gian quy định. Vui lòng thử lại.';
                __showError(message, liveness, true);
            } else if (data.status === 1) {
                __stop(true);
                message = 'Đạt.';
                if (data.error.code !== 0 && data.error.code !== 21) {
                    message = 'Không đạt, vui lòng thử lại.';
                    __showError(message, liveness, true);
                }
                else {
                    __guideTitle.text('Vui lòng chờ trong giây lát...');
                    // save selfie
                    localStorage.setItem('selfie_dataurl', 'data:image/jpeg;base64,' + data.base64_image);
    
                    __confirmResults();            
                }
            } else {
                message = LIVENESS_MESSAGES[data.message];
                // render message;
                if (message === 'success') {
                    __successIcon.css('display', 'block');
                    __guideIcons[__lvns_step - 1].css({opacity: 1.0});
                    __lvns_step = __lvns_step + 1;
                    setTimeout(function () {
                        __successIcon.css('display', 'none');
                    }, 2000)
                } else {                    
                    if (message != LIVENESS_MESSAGES.Processing) {
                        console.log("Liveness step " + __lvns_step)
                        if (__lvns_step >= 4) {
                            if (__lvns_step == 4) {
                                __guideIcons.forEach(x => x.hide());
                            }
                            else {
                                __guideIcons[__lvns_step - 2].hide();
                            }

                            let added_icon = __options.style.photos.HoldSteady2Second;
                            switch (message) {
                                case LIVENESS_MESSAGES.TurnLeft:
                                    added_icon = __options.style.photos.TurnLeft;
                                    break;
                                case LIVENESS_MESSAGES.TurnRight:
                                    added_icon = __options.style.photos.TurnRight;
                                    break;
                                case LIVENESS_MESSAGES.TurnUp:
                                    added_icon = __options.style.photos.TurnUp;
                                    break;
                                case LIVENESS_MESSAGES.TurnDown:
                                    added_icon = __options.style.photos.TurnDown;
                                    break;
                            }   
                            __guideIcons.push(jQuery('<img/>', {        
                                src: added_icon, 
                                css: {
                                    opacity: "0.5",
                                    width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375),
                                    margin: "15px"
                                },            
                            }).insertBefore(__guideTitle));
                        }                                                 
                    }
                    __guideTitle.text(message);
                }            
            }

        }
    };

    var __addTracks = function () {
        var isFirefox = typeof InstallTrigger !== 'undefined';
        let videoParams;
        if (!isFirefox) {
            videoParams = {
                width: 640,
                height: 640,
                frameRate: {
                    max: 10
                }
            }
        }
        else {
            videoParams = {
                width: 640,
                height: 640
            }
        }
        navigator.mediaDevices.getUserMedia({
            video: videoParams
        }).then(function (stream) {
            __webcam.get(0).srcObject = stream;

            __webcam.get(0).play();

            stream.getTracks().forEach(function (track) {
                __pc.addTrack(track, stream);
            });

            __negotiate();
        }).catch(function (err) {
            console.log(err);
        });
    };

    var __negotiate = function () {
        __pc.createOffer().then(function (offer) {
            __pc.setLocalDescription(offer);
            return offer;
        }).then(function (offer) {
            return new Promise(function (resolve) {
                function ____checkState() {
                    if (__pc.iceGatheringState === 'complete') {
                        __pc.removeEventListener('icegatheringstatechange', ____checkState);
                        resolve();
                    }
                }

                if (__pc.iceGatheringState === 'complete') {
                    resolve();
                } else {
                    __pc.addEventListener('icegatheringstatechange', ____checkState)
                }
            })
        }).then(function () {
            var offer = __pc.localDescription;
            return fetch(__options.host + '/api/kyc/liveness/offer/v2', {
                body: JSON.stringify({
                    sdp: __sdpFilterCodec('video', 'VP8/90000', offer.sdp),
                    type: offer.type,
                    video_transform: 'none',
                    version: "2",
                    is_save_result: true,
                    // use_additional_check: true,
                    session_id: localStorage.getItem('session_token')
                }),
                headers: {
                    'Content-Type': 'application/json',
                    "Authorization": localStorage.getItem('session_token')
                },
                method: 'POST'
            })
        }).then(function (response) {
            return response.json();
        }).then(function (answer) {
            console.log(LIVENESS_MESSAGES['Initializing']);
            return __pc.setRemoteDescription(answer);
        }).catch(function (err) {
            console.log(err);
        });
    };

    var __sdpFilterCodec = function (kind, codec, realSdp) {
        var allowed = [];
        var rtxRegex = new RegExp('a=fmtp:(\\d+) apt=(\\d+)\r$');
        var codecRegex = new RegExp('a=rtpmap:([0-9]+) ' + __escapeRegExp(codec))
        var videoRegex = new RegExp('(m=' + kind + ' .*?)( ([0-9]+))*\\s*$')

        var lines = realSdp.split('\n');

        var isKind = false;
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].startsWith('m=' + kind + ' ')) {
                isKind = true;
            } else if (lines[i].startsWith('m=')) {
                isKind = false;
            }

            if (isKind) {
                var match = lines[i].match(codecRegex);
                if (match) {
                    allowed.push(parseInt(match[1]));
                }

                match = lines[i].match(rtxRegex);
                if (match && allowed.includes(parseInt(match[2]))) {
                    allowed.push(parseInt(match[1]));
                }
            }
        }

        var skipRegex = 'a=(fmtp|rtcp-fb|rtpmap):([0-9]+)';
        var sdp = '';

        isKind = false;
        for (let i = 0; i < lines.length; i++) {
            if (lines[i].startsWith('m=' + kind + ' ')) {
                isKind = true;
            } else if (lines[i].startsWith('m=')) {
                isKind = false;
            }

            if (isKind) {
                var skipMatch = lines[i].match(skipRegex);
                if (skipMatch && !allowed.includes(parseInt(skipMatch[2]))) {
                    continue;
                } else if (lines[i].match(videoRegex)) {
                    sdp += lines[i].replace(videoRegex, '$1 ' + allowed.join(' ')) + '\n';
                } else {
                    sdp += lines[i] + '\n';
                }
            } else {
                sdp += lines[i] + '\n';
            }
        }

        return sdp;
    };

    var __escapeRegExp = function (string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    };

    var __stop = function (stopWebcam=false) {
        if (__dc) {
            __dc.close();
        }

        if (__pc.getTransceivers) {
            __pc.getTransceivers().forEach(function(transceiver) {
                if (transceiver.stop) {
                    transceiver.stop();
                }
            });
        }
        
        if (stopWebcam) {
            __pc.getSenders().forEach(function(sender) {
                try {
                    sender.track.stop();
                } catch {
                    console.log("Track closed already");
                }
            });
            
            __webcam.get(0).srcObject.getTracks().forEach(function(track) {
                track.stop();
            });
            console.log("stopped webcam")
        }
        
        setTimeout(function () {
            __pc.close();
        }, 500);

    };

    // END: Liveness functions
    var __getErrorMessage = function (errorCode) {
        if (__options.error_messages[errorCode]) {
            return __options.error_messages[errorCode] + '. Vui lòng thử lại.';
        } else {
            return 'Lỗi hệ thống. Vui lòng thử lại.';
        }
    };

    var __convertToSlug = function (str) {
        str = str.toUpperCase();

        str = str
            .normalize('NFD')
            .replace(/[\u0300-\u036f]/g, '');

        str = str.replace(/[đĐ]/g, 'd');

        str = str.replace(/([^0-9A-Z-\s])/g, '');

        str = str.replace(/(\s+)/g, '-');

        str = str.replace(/-+/g, '-');

        str = str.replace(/^-+|-+$/g, '');

        return str;
    };

    var __getDataUrl = function (imageFile) {
        var reader = new FileReader();
        // reader.onloadend = function (e) {
        //     cb(e.target.result, e.target.error);
        // };
        reader.readAsDataURL(imageFile);
        reader.onload = function () {
            localStorage.setItem('selfie_dataurl', reader.result);
        };
        reader.onerror = function (error) {
          console.log('Error: ', error);
        };
    };

    var __getBlob = function (dataURI) {
        // convert base64 to raw binary data held in a string
        // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this
        var byteString = atob(dataURI.split(',')[1]);

        // separate out the mime component
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];

        // write the bytes of the string to an ArrayBuffer
        var ab = new ArrayBuffer(byteString.length);
        var ia = new Uint8Array(ab);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }

        //New Code
        return new Blob([ab], {type: mimeString});
    };

    var __showError = function (errorMessage, confirmCallback, callBackArgument) {
        if (Swal) {
            Swal.fire({
                icon: 'error',
                html: `<small style="font-size: .775em; color: ${__options.style.textColor}">${errorMessage}</small>`,
                customClass: {
                    icon: 'swal2-icon-small',
                },
                target: __options.wrap_id,
                background: "rgb(22, 31, 45, 0.9)",
                confirmButtonColor: "rgb(2, 253, 174, 0.75)",
                width: "90%",
            }).then((result) => {
                if (result.isConfirmed) {
                    if (confirmCallback) confirmCallback(callBackArgument);
                }
            });
            jQuery(".swal2-container").css({
                position: "absolute"
            });
        } else {
            alert(errorMessage)
        }
    };

    var __showWarning = function (errorMessage, confirmCallback, callBackArgument) {
        if (Swal) {
            Swal.fire({
                icon: 'warning',
                html: `<small style="font-size: .775em; color: ${__options.style.textColor}">${errorMessage}</small>`,
                customClass: {
                    icon: 'swal2-icon-small',
                },
                target: __options.wrap_id,
                background: "rgb(22, 31, 45, 0.9)",
                confirmButtonColor: "rgb(2, 253, 174, 0.75)",
                width: "90%",
            }).then((result) => {
                if (result.isConfirmed) {
                    if (confirmCallback) confirmCallback(callBackArgument);
                }
            });
            jQuery(".swal2-container").css({
                position: "absolute"
            });
        } else {
            alert(errorMessage)
        }
    };

    var __clearLayout = function () {
        jQuery(__options.wrap_id).html(
            null
        );
        __wrapper = jQuery("<div/>", {
            css: {
                height: "100%",
                minHeight: 500,
                position: 'relative',
                backgroundColor: __options.style.backgroundColor,
                textAlign: "center"
            }
        }).appendTo(__options.wrap_id);

        footer = jQuery("<img/>", {
            src: __options.style.photos.footer,
            css: {
                position: "absolute",
                bottom: 0,
                width: "100%",
                opacity: 0.45,
                left: 0
            }
        }).appendTo(__wrapper);
    };

    var __clearLocalStorage = function () {
        localStorage.clear();
    };

    var renderResult = function () {
        jQuery(__options.wrap_id).html(null);
        __wrapper = jQuery("<div/>", {
            css: {
                height: "100%",
                minHeight: 500
            }
        }).appendTo(__options.wrap_id);

        overflow_wrap = jQuery("<div/>", {
            css: {
                position: "absolute",
                top: 0,
                width: "100%",
            }
        }
        ).appendTo(__wrapper)

        footer = jQuery("<img/>", {
            src: __options.style.photos.footer,
            css: {
                position: "absolute",
                bottom: 0,
                width: "100%",
                left: 0
            }
        }).appendTo(overflow_wrap);  
        
        var selfieData, antifraudData, verifyData, idData, qrCodeData, mrzData, dlData;
        try {
            selfieData = JSON.parse(localStorage.getItem('selfie')).data;
        }
        catch {
            selfieData = null;
        }
        try {
            antifraudData = JSON.parse(localStorage.getItem('antifraud')).results;
        }
        catch {
            antifraudData = null;
        }        
        try {
            dlData = JSON.parse(localStorage.getItem('decision_details'));            
        } 
        catch {
            dlData = null;
        }
        try {
            verifyData = JSON.parse(localStorage.getItem('verify'));
        } 
        catch {
            verifyData = null;
        }
        try {
            idData = JSON.parse(localStorage.getItem('ocr_data'));
        }
        catch {
            idData = null;
        }
        try {
            qrCodeData = JSON.parse(localStorage.getItem('qr_decode'));
        }
        catch {
            qrCodeData = null;
        }
        try {
            mrzData = JSON.parse(localStorage.getItem('mrz_decode'));
        }
        catch {
            mrzData = null;
        }        

        // var dl_checks = {
        //     "LG_01": "Độ dài ID phù hợp với loại thẻ",
        //     "LG_02": "Ngày sinh và giới tính khớp với ID",
        //     "LG_03": "Địa chỉ khớp với ID",
        //     "LG_04": "Ngày cấp, ngày sinh, ngày hết hạn không bất thường",
        //     "LG_06": "Ảnh mặt trước và mặt sau cùng một loại",
        //     "LG_07": "Ảnh mặt trước và mặt sau có cùng điều kiện ánh sáng"
        // };
        // var dl_results = [];
        // if (dlData) {
        //     dlData.map(x => {
        //         if (Object.keys(dl_checks).includes(x.code)) {
        //             dl_results.push({
        //                 description: x.description_vi ? x.description_vi : x.description ? x.description : dl_checks[x.code],
        //                 pass: x.is_pass
        //             });
        //         }
        //     });
        // }
        // else {
        //     Object.keys(dl_checks).map(x => {
        //         dl_results.push({
        //             description: dl_checks[x],
        //             pass: null
        //         });
        //     })
        // }

        // console.log(dl_results);
        console.log(dlData);
        
        jQuery("<div/>", {
            html: `<img style="width: 200px;
                height: 200px;
                object-fit: cover;
                border-radius: 100%; 
                border: 3px solid #02FDAE;
                box-shadow: 2px 0px 5px #02FDAE, -2px 0px 5px #02FDAE;
                " src=${localStorage.getItem('selfie_dataurl')} />                  
                <br/>
                <img style="height: 60px;" src="${__options.style.photos.loading}" id="frontImage" />
                <br/>
                <img style="height: 60px;" src="${__options.style.photos.loading}" id="backImage" />
                <div style="color: ${__options.style.textColor};font-size: 0.9rem; font-weight: 700; padding: 2%">`
                + 
                (
                    localStorage.getItem("decision") != "REJECTED" ?
                    `<span style="line-height: 15px">Đăng ký thành công. </span>
                    <p style="line-height: 15px">Hồ sơ của bạn đang được xét duyệt.</p>` :
                    `<span style="line-height: 15px">Đăng ký không thành công. </span>
                    <p style="line-height: 15px">Đã có vấn đề xảy ra với hồ sơ của bạn.</p> 
                    <p style="line-height: 15px">Vui lòng kiểm tra lại thông tin.</p>`
                )
                + 
                `</div>
            `,                
            css: {
                width: "100%",                    
                marginTop: "10%"
            }
        }).appendTo(overflow_wrap);
        
        axios.get(__options.host + "/api/data/image?type=FRONT", {
            headers: {
                'Authorization': localStorage.getItem('session_token')
            },
            responseType: 'blob'
            }).then(function (response) {
    
            var reader = new window.FileReader();
            reader.readAsDataURL(response.data); 
            reader.onload = function() {
    
                var imageDataUrl = reader.result;
                $("#frontImage").attr("src", imageDataUrl);
                $("#frontImage").attr("style", "border: 1px solid #02FDAE; box-shadow: 2px 0px 5px #02FDAE, -2px 0px 5px #02FDAE; width: 80%; max-width: 300px; margin: 20px;");
            }
        })
        
        axios.get(__options.host + "/api/data/image?type=BACK", {
            headers: {
                'Authorization': localStorage.getItem('session_token')
            },
            responseType: 'blob'
            }).then(function (response) {
    
            var reader = new window.FileReader();
            reader.readAsDataURL(response.data); 
            reader.onload = function() {
    
                var imageDataUrl = reader.result;
                $("#backImage").attr("src", imageDataUrl);
                $("#backImage").attr("style", "border: 1px solid #02FDAE; box-shadow: 2px 0px 5px #02FDAE, -2px 0px 5px #02FDAE; width: 80%; max-width: 300px; margin: 20px;");
            }
        })
        
        results_wrap = jQuery("<div/>", {
            css: {
                "position": "relative",
                "width": "100%",
                "marginTop": "5%",                  
                "marginBottom": "20%"
            }
        }).appendTo(overflow_wrap);

        results = jQuery("<div/>", {
            css: {
                "position": "relative",
                "width": "100%",
                "maxWidth": 500,
                "padding": 0,
                "margin": "0 auto"                                                    
            }
        }).appendTo(results_wrap);

        var isFirefox = typeof InstallTrigger !== 'undefined';
        if (!isFirefox) {
            jQuery('<div/>', {            
                css: {
                    height: '100%',
                    position: "absolute",
                    top: "0",
                    width: "65%",
                    left: "50%",
                    transform: "translateX(-50%)",
                    background: "rgba(2, 253, 174, 0.15)",
                    border: "none"
                    // border: "1px solid #02FDAE",
                    // borderBottom: "none",
                    // borderTop: "none"
                }
            }).appendTo(results);
    
            jQuery('<div/>', {            
                css: {
                    height: '100%',
                    position: "absolute",
                    top: "0",
                    width: "60%",
                    left: "50%",
                    transform: "translateX(-50%)",                    
                    border: "1px solid rgb(2, 253, 174, 0.39)",
                    borderBottom: "none",
                    borderTop: "none"
                }
            }).appendTo(results);
    
    
            jQuery('<div/>', {            
                css: {
                    height: '100%',
                    position: "absolute",
                    top: "0",
                    width: "70%",
                    left: "50%",
                    transform: "translateX(-50%)",
                    border: "1px solid rgb(2, 253, 174, 0.39)",
                    borderBottom: "none",
                    borderTop: "none"
                }
            }).appendTo(results);
        }

        jQuery('<div/>', {
            id: 'personal_information',
            html: 
                __sessionPlan != "PLAN_PASSPORT_BASIC" ?
                (
                    `<p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">Thông tin OCR</p>
                    <div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.id_number}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.name}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.birthday}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.gender}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Quê quán</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.home}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Địa chỉ</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.resident}</div>
                    </div><hr>` +
                    (idData && idData.doi ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doi}</div>
                    </div><hr>` : '') +
                    
                    (idData && idData.doe ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doe}</div>
                    </div><hr>` : '') +
                    
                    (idData && idData.features ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Đặc điểm nhận dạng</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.features}</div>
                    </div><hr>` : '') +                
                    
                    (idData && idData.poi ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.poi}</div>
                    </div><hr>` : '') +
                    
                    (idData && idData.religion ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Tôn giáo</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.religion}</div>
                    </div><hr>` : '') +
                    (idData && idData.ethnicity ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Dân tộc</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.ethnicity}</div>
                    </div><hr>` : '') +
                    (qrCodeData != null && qrCodeData.data != null && typeof(qrCodeData.data.decoded_text) == "string" ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">QR Code</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right; word-wrap: break-word">${qrCodeData.data.decoded_text.replaceAll("|", "; ")}</div>
                    </div><hr>` : '') +
                    (mrzData != null && mrzData.data != null && typeof(mrzData.data.raw_mrz) == "string" ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">MRZ Code</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right; word-wrap: break-word">${mrzData.data.raw_mrz.replaceAll("<", "‹").replaceAll("\n", "")}</div>
                    </div><hr>` : '')
                ) : (
                    `<p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">Thông tin OCR</p>`
                    +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.id_number}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Passport ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.pp_number}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.name}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.dob}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.gender}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Quốc tịch</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.nationality}</div>
                    </div><hr>` +
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi sinh</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.pob}</div>
                    </div><hr>` +
                    (idData && idData.doi ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doi}</div>
                    </div><hr>` : '') +
                    
                    (idData && idData.doe ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doe}</div>
                    </div><hr>` : '') +
                    
                    (idData && idData.poi ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.poi}</div>
                    </div><hr>` : '') +
                    
                    (idData && idData.type ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Loại</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.type}</div>
                    </div><hr>` : '') +
                    (idData && idData.code ?
                    `<div style="display: flex">
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Mã số</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.code}</div>
                    </div><hr>` : '')
                ),                     
            css: {                
                textAlign: 'left',
                background: "rgba(255, 255, 255, 0.2)",
                border: "1px solid #02FDAE",
                boxSizing: "border-box",
                boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)",
                backdropFilter: "blur(24px)",
                borderRadius: "19px",
                padding: "5%",
                width: "80%",
                margin: "0 auto",
                color: __options.style.textColor,
                fontSize: "0.8rem"
            }
        }).appendTo(results);
        
        if (__allowFullResults) {
            jQuery('<div/>', {
                    html: 
                    `
                    <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">So khớp khuôn mặt</p>
                    <div>
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Độ tương đồng</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${(selfieData.matching_score).toFixed(2)}%</div>
                    </div><hr>` +
                    `<div>
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Kết quả</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"><img style="height: 15px; width: 15px" src='${selfieData.is_matched ? __options.style.photos.pass : __options.style.photos.notPass}'/></div>
                    </div><hr>` 
                    ,
                    css: {
                        textAlign: 'left',
                        background: "rgba(255, 255, 255, 0.2)",
                        border: "1px solid #02FDAE",
                        boxSizing: "border-box",
                        boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)",
                        backdropFilter: "blur(24px)",
                        borderRadius: "19px",
                        padding: "5%",
                        width: "80%",
                        margin: "0 auto",
                        color: __options.style.textColor,
                        fontSize: "0.8rem",
                        marginTop: "10%"
                    }
            }).appendTo(results);        
            
            if ((__sessionPlan == "PLAN_BASIC") || (__sessionPlan == "PLAN_PLUS")) {

                jQuery('<div/>', {
                    html: 
                    `
                        <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">So khớp thông tin</p>
                        <div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Họ tên - ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"><img style="height: 15px; width: 15px" src='${(verifyData.verified === undefined || verifyData.verified == null) ? __options.style.photos.unknown : verifyData.verified ? __options.style.photos.pass : __options.style.photos.notPass}'/></div>
                            </div><hr>` + 
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Khuôn mặt - ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${(antifraudData == null || antifraudData.verify_face_id == undefined || Object.keys(antifraudData.verify_face_id).length == 0) ? `<img style="height: 15px; width: 15px" src='${__options.style.photos.unknown}'/>` : `<img style="height: 15px; width: 15px" src="${antifraudData.verify_face_id.matched ? __options.style.photos.pass : __options.style.photos.notPass}"/>`}</div>
                        </div><hr>`,
                    css: {
                        textAlign: 'left',
                        background: "rgba(255, 255, 255, 0.2)",
                        border: "1px solid #02FDAE",
                        boxSizing: "border-box",
                        boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)",
                        backdropFilter: "blur(24px)",
                        borderRadius: "19px",
                        padding: "5%",
                        width: "80%",
                        margin: "0 auto",
                        color: __options.style.textColor,
                        fontSize: "0.7rem",
                        marginTop: "10%"
                    }
                }).appendTo(results);
            }
            
            if (__sessionPlan == "PLAN_FULL") {

                dlContent = '';
                dlData.map(x => {
                    if (x.is_pass != 1) {
                        dlContent = dlContent + `
                        <div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">${x.description_vi}</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${x.is_pass == -1 ? `<img style="height: 15px; width: 15px" src='${__options.style.photos.unknown}'/>` : `<img style="height: 15px; width: 15px" src='${x.is_pass == 1 ? __options.style.photos.pass : __options.style.photos.notPass}'/>`}</div>
                        </div><hr>
                        `
                    }
                })

                if (dlContent == '') {
                    dlContent = `
                    <div>
                        <div style="padding: 5px 0; width: 50%; display: inline-block">Không có</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"></div>
                    </div>`
                }

                jQuery('<div/>', {
                    html: 
                    `
                        <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">Dấu hiệu bất thường, gian lận</p>`

                    +
                    dlContent                        
                    ,
                    css: {
                        textAlign: 'left',
                        background: "rgba(255, 255, 255, 0.2)",
                        border: "1px solid #02FDAE",
                        boxSizing: "border-box",
                        boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)",
                        backdropFilter: "blur(24px)",
                        borderRadius: "19px",
                        padding: "5%",
                        width: "80%",
                        margin: "0 auto",
                        color: __options.style.textColor,
                        fontSize: "0.8rem",
                        marginTop: "10%"
                    }
                }).appendTo(results);                        
            }

            faceSearchContent = '';
            try {
                faceSearchData = JSON.parse(localStorage.getItem("faceSearchData"));
                faceSearchData.nearests.map(x => {
                    faceSearchContent = faceSearchContent + `
                        <div>
                            <div style="padding: 5px 0; width: 70%; display: inline-block"><img style="width: 100%; border:` + `${x[3] ? '2px solid rgb(2, 253, 174)' : '2px solid red' }` + `" src="data:image/jpg;base64,${x[0]}"></div><div style="padding: 5px 0; width: 30%; display: inline-block; text-align: right"><img style="width: 80%; border:` + `${x[3] ? '2px solid rgb(2, 253, 174)' : '2px solid red' }` + `" src="data:image/jpg;base64,${x[1]}"></div>
                        </div>
                        `
                })
            }
            catch {
                faceSearchContent = `
                    <div>
                        <div style="padding: 5px 0; display: inline-block">${localStorage.getItem("faceSearchData")}</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"></div>
                    </div>
                `
            }

            jQuery('<div/>', {
                html: 
                `
                    <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">ID(s) có gương mặt tương tự</p>`

                +
                faceSearchContent                        
                ,
                css: {
                    textAlign: 'left',
                    background: "rgba(255, 255, 255, 0.2)",
                    border: "1px solid #02FDAE",
                    boxSizing: "border-box",
                    boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)",
                    backdropFilter: "blur(24px)",
                    borderRadius: "19px",
                    padding: "5%",
                    width: "80%",
                    margin: "0 auto",
                    color: __options.style.textColor,
                    fontSize: "0.8rem",
                    marginTop: "10%"
                }
            }).appendTo(results);    
        }
        
        jQuery('<div/>', {          
            html: `
                <p style="font-size: 0.8rem; line-height: 40px; font-weight: 600; color: #696969;">Thử lại</p>
            `,  
            css: {
                height: '40px',
                cursor: "pointer", 
                width: "100px",
                backgroundColor: "#02FDAE",
                borderRadius: "21.35px",
                margin: "30px auto"
            },
            on: {
                click: function () {                    
                    initSession();
                }
            }
        }).appendTo(results_wrap);

    };    

    var liveness = function (isRestart=false) {
        if (isRestart) {
            __createPeerConnection();
            __createDataChannel();
            __handleMessageEvent();

            stream = __webcam.get(0).srcObject;
            stream.getTracks().forEach(function (track) {
                __pc.addTrack(track, stream);
            });

            __negotiate();
            __lvns_step = 1;

            if (__guideIcons.length > 3) {
                console.log(__guideIcons.length);
                let tmp = __guideIcons.length;
                for (let idx = 3; idx < tmp; idx ++) {
                    __guideIcons[idx].remove();                    
                }
                for (let idx = 3; idx < tmp; idx ++) {
                    __guideIcons.pop();
                }
                console.log(__guideIcons.length);
            }
            __guideIcons.forEach(child => {
                child.css({
                    display: "inline-block",
                    opacity: 0.5
                })
            });
            __warningIcon.hide();

            __guideTitle.text(LIVENESS_MESSAGES.Initializing);
        }
        else {

            __clearLayout();        

            __guideIcons = [];
            __lvns_step = 1;

            var webcamWrap;
            var header = jQuery(
                `
                <div style="width: 80%; position: absolute; top: 5%; 
                    left: 50%; -webkit-transform: translateX(-50%);
                    transform: translateX(-50%); height: 20px">
                    <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">Xác thực sự sống</p>                
                </div>
                `,
            ).appendTo(__wrapper);
            
            // var backBtn = jQuery("<span/>", {
            //     html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`,
            //     css: {
            //         float: "left",
            //         cursor: "pointer",
            //         height: "20px",
            //         marginTop: "-20px",
            //         width: "20px",
            //         backgroundColor: __options.style.headlineButtonStyle.backgroundColor,
            //         borderRadius: "100%"
            //     },
            //     on: {
            //         click: () => backToUploadID("back")
            //     }
            // }).appendTo(header);
    
            webcamWrap = jQuery('<div/>', {
                css: {
                    position: 'absolute',
                    top: "15%",
                    width: '100%',
                    height: "50%",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center"
                }
            }).appendTo(__wrapper);        
    
            __webcam = jQuery('<video/>', {
                autoplay: true,
                playsinline: true,
                css: {           
                    position: "absolute",     
                    maxHeight: '100%',
                    height: Math.min(300, jQuery(__wrapper).height() * 0.4, jQuery(__wrapper).width() * 0.7),
                    width: Math.min(300, jQuery(__wrapper).height() * 0.4, jQuery(__wrapper).width() * 0.7),
                    objectFit: 'cover',
                    borderRadius: '100%',                
                    transform: "scale(-1, 1)"
                }
            }).appendTo(webcamWrap);
    
            cameraFrame = jQuery('<img/>', {
                src: "./static/_pngtree_round_yellow_light_effect_6670101_1.png",            
                css: {           
                    position: "absolute",     
                    maxHeight: '100%',
                    width: "270px",
                    objectFit: 'cover',
                    borderRadius: '100%',     
                    animationName: "spin",
                    animationDuration: "5000ms",
                    animationIterationCount: "infinite",
                    animationTimingFunction: "linear"            
                }
            }).appendTo(webcamWrap);
    
            
            __guideBox = jQuery('<div/>', {                                    
                css: Object.assign({
                    position: "absolute",
                    textAlign: "center",
                    bottom: "10%",
                    left: "50%",
                    width: "80%",
                    maxWidth: "300px",
                    transform: "translateX(-50%)"         
                }, __options.style.guideBoxStyle),            
            }).appendTo(__wrapper);
    
            __guideIcons.push(jQuery('<img/>', {        
                src: __options.style.photos.HoldSteady2Second,                
                css: {
                    opacity: "0.5",
                    width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375),
                    margin: "15px"
                },            
            }).appendTo(__guideBox));

            __guideIcons.push(jQuery('<img/>', {        
                src: __options.style.photos.TurnDown,                
                css: {
                    opacity: "0.5",
                    width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375),
                    margin: "15px"
                },            
            }).appendTo(__guideBox));

            __guideIcons.push(jQuery('<img/>', {        
                src: __options.style.photos.TurnLeft,                
                css: {
                    opacity: "0.5",
                    width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375),
                    margin: "15px"
                },            
            }).appendTo(__guideBox));            
            
            __guideTitle = jQuery('<p/>', {        
                text: LIVENESS_MESSAGES.Initializing,
                css: {
                    fontSize: "0.9rem",
                    fontWeight: 500,
                    marginBottom: "5%"
                },            
            }).appendTo(__guideBox);
    
            __successIcon = jQuery('<img/>', {
                src: __options.style.photos.LivenessSuccessIcon,
                css: {
                    position: "absolute",
                    display: 'none',                                
                    borderRadius: '100%',
                    background: 'white',
                    width: '80px'
                }
            }).appendTo(webcamWrap);
    
            __warningIcon = jQuery('<img/>', {
                src: __options.style.photos.LivenessWarningIcon,
                css: {
                    display: 'none',
                    position: "absolute",
                    borderRadius: '100%',
                    background: 'white',
                    width: '80px'
                }
            }).appendTo(webcamWrap);
    
            __createPeerConnection();
            __createDataChannel();
            __handleMessageEvent();
            __addTracks();
        }
    };

    var scanQrCode = () => {
        __clearLayout();
        
        var qrScanner;

        var canvas;

        var webcam;

        var webcamWrap;

        var header = jQuery(
            `
            <div style="width: 80%; position: absolute; top: 5%; 
                left: 50%; -webkit-transform: translateX(-50%);
                transform: translateX(-50%); height: 20px">
                <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">Quét QR Code</p>                
            </div>
            `,
        ).appendTo(__wrapper);
        
        // var backBtn = jQuery("<span/>", {
        //     html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`,
        //     css: {
        //         float: "left",
        //         cursor: "pointer",
        //         height: "20px",
        //         marginTop: "-20px",
        //         width: "20px",
        //         backgroundColor: __options.style.headlineButtonStyle.backgroundColor,
        //         borderRadius: "100%"
        //     },
        //     on: {
        //         click: () => backToUploadID("front")
        //     }
        // }).appendTo(header)
        
        webcamHeight = parseInt(jQuery(__wrapper).height() * 0.35);
            console.log(webcamHeight);
            webcamWrap = jQuery('<div/>', {
                css: {
                    position: 'absolute',
                    top: "10%",                    
                    width: "100%",
                    height: webcamHeight,
                    backgroundColor: "black",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    left: "50%",
                    transform: "translateX(-50%)"
                }
            }).appendTo(__wrapper);
            

        webcam = jQuery('<video/>', {
            autoplay: true,
            playsinline: true,
            css: {
                width: "100%",
                height: webcamHeight,
                // transform: "scale(-1, 1)"                
            }
        }).appendTo(webcamWrap);

        canvas = jQuery('<canvas/>', {
            css: {
                left: "50%",
                transform: "translateX(-50%)",                    
                height: webcamHeight,
                position: 'absolute',
                top: "10%",
                display: 'none'
            }                
        }).appendTo(__wrapper);
        
        QrScanner.WORKER_PATH = './static/qr-scanner-worker.min.js';
        qrScanner = new QrScanner(webcam[0], result => {
            // Swal.fire({
            //     icon: 'success',
            //     title: 'QR COde',
            //     text: result,
            // });
            qrScanner.destroy();
            qrScanner = null;
            webcam.get(0).srcObject.getTracks().forEach(function(track) {
                track.stop();
            });
            localStorage.setItem('qr_decode', result);  
            uploadId("back");
        }, error => console.log(error || 'No QR code found.'));            
                
        navigator.mediaDevices.getUserMedia({
            video: {
                width: { ideal: __options.using_mobile ? 720 : 1280 },
                height: { ideal: __options.using_mobile ? 1280: 720 },
                facingMode: 'environment'
            },
            audio: false
        }).then(function (stream) {
            webcam.get(0).srcObject = stream;
            webcam.get(0).play();
            qrScanner.start();

            setTimeout(() => {
                if (localStorage.getItem("qr_decode") === null) {
                    qrScanner.destroy();
                    qrScanner = null;
                    webcam.get(0).srcObject.getTracks().forEach(function(track) {
                        track.stop();
                    });
                    uploadId("back");
                }
            }, __options.qrCodeTimeOut * 1000);

            let stream_settings = stream.getVideoTracks()[0].getSettings();

            // actual width & height of the camera video
            let stream_width = stream_settings.width;
            let stream_height = stream_settings.height;
            
            if (webcamHeight * stream_width / stream_height > jQuery(__wrapper).width()) {
                // webcam falls to width=100%
                webcam_actual_height = jQuery(__wrapper).width() * stream_height / stream_width;

                webcamWrap.css({
                    height: webcam_actual_height
                });
                
                webcam.css({
                    height: webcam_actual_height
                });
                canvas.css({
                    height: webcam_actual_height
                });

            }
            else {
                webcam_actual_height = webcamHeight;
            }
            console.log(stream_width, stream_height);

            jQuery('<img/>', {
                src: __options.style.photos.cameraFrameLarge,
                css: {
                    height: webcam_actual_height * 0.6,
                    width: webcam_actual_height * 0.6,                   
                    position: "absolute",
                    background: "rgba(2, 253, 174, 0.4)",
                    borderRadius: "16px"
                }
            }).appendTo(webcamWrap);
                
        }).catch(function (err) {
            console.log(err);
        })
    }

    var uploadId = function (side) {
        __clearLayout();

        var inputFile;

        var canvas;

        var webcam;

        var webcamWrap;

        var guide;
        
        var header = jQuery(
            side == "qr" ? 
            `
            <div style="width: 80%; position: absolute; top: 5%; 
                left: 50%; -webkit-transform: translateX(-50%);
                transform: translateX(-50%); height: 20px">
                <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} ảnh vùng QR Code</p>                
            </div>
            `
            : side == "selfie" ?
            `
            <div style="width: 80%; position: absolute; top: 5%; 
                left: 50%; -webkit-transform: translateX(-50%);
                transform: translateX(-50%); height: 20px">
                <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} ảnh chân dung</p>                
            </div>
            `
            :
            `
            <div style="width: 80%; position: absolute; top: 5%; 
                left: 50%; -webkit-transform: translateX(-50%);
                transform: translateX(-50%); height: 20px">
                <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} ảnh ${__sessionPlan != "PLAN_PASSPORT_BASIC" ? "CMND/CCCD" : "Passport"} mặt ${side == 'front' ? 'trước' : 'sau' }</p>                
            </div>
            `,
        ).appendTo(__wrapper);
        
        // var backBtn = jQuery("<span/>", {
        //     html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`,
        //     css: {
        //         float: "left",
        //         cursor: "pointer",
        //         height: "20px",
        //         marginTop: "-20px",
        //         width: "20px",
        //         backgroundColor: __options.style.headlineButtonStyle.backgroundColor,
        //         borderRadius: "100%"
        //     },
        //     on: {
        //         click: () => side == "back" ? backToUploadID("front") : backToUploadID("back")
        //     }
        // })

        // if (side == "back" || side == "selfie") {
        //     backBtn.appendTo(header)
        // }

        var previewImage = jQuery('<img/>', {
            src: (__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront,
            css: {
                display: __uploadType === 'UPLOAD' ? 'block' : 'none',
                maxHeight: jQuery(__wrapper).innerHeight() * 0.4 ,                            
                width: '80%',
                maxWidth: "300px",
                position: 'absolute',
                top: '10%',
                left: "50%",
                transform: "translateX(-50%)"
            }}).appendTo(__wrapper);

        if (__uploadType === 'UPLOAD') {
            inputBtn = jQuery('<label/>', {
                html: `<p style="font-weight: 600">Chọn ảnh</p>`,
                css: Object.assign({
                    position: "absolute",
                    width: "96px",
                    height: "44px",
                    top: '60%',
                    left: "50%",
                    transform: "translateX(-50%)",
                    borderRadius: "21.35px"
                }, __options.style.snapshotButtonStyle)

            }).appendTo(__wrapper)

            inputFile = jQuery('<input/>', {
                type: 'file',
                accept: 'image/*',
                // capture: 'camera',
                css: {
                    display: 'none'
                },
                on: {
                    change: function (e) {
                        console.log(inputFile.get(0).files[0]);
                        if (inputFile.get(0).files[0]) {
                            previewImage.prop('src', URL.createObjectURL(e.target.files[0]));
                            
                            inputBtn.css({
                                left: "50%",
                                transform: "translateX(-150%)"
                            })

                            nextButton.css({
                                "display": "flex",
                                "pointerEvents": "auto"
                            });

                        } else {
                            previewImage.prop('src', (__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront);
                        }
                    }
                }
            }).appendTo(inputBtn);
            
        }

        var takeSnapshotForWebrtc;
        if (__uploadType === "WEBRTC") {
            webcamHeight = parseInt(jQuery(__wrapper).height() * 0.35);
            console.log(webcamHeight);
            webcamWrap = jQuery('<div/>', {
                css: {
                    position: 'absolute',
                    top: "10%",                    
                    width: "100%",
                    height: webcamHeight,
                    backgroundColor: "black",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    left: "50%",
                    transform: "translateX(-50%)"
                }
            }).appendTo(__wrapper);
            

            webcam = jQuery('<video/>', {
                autoplay: true,
                playsinline: true,
                css: {
                    width: "100%",
                    height: webcamHeight,
                    // transform: "scale(-1, 1)"                
                }
            }).appendTo(webcamWrap);

            canvas = jQuery('<canvas/>', {
                css: {
                    left: "50%",
                    transform: "translateX(-50%)",                    
                    height: webcamHeight,
                    position: 'absolute',
                    top: "10%",
                    display: 'none'
                }                
            }).appendTo(__wrapper);            

            if (jQuery(__wrapper).height() * 0.23 > 180) {
                guide = jQuery('<div/>', {
                    html: 
                    `
                    <p style="font-size: 0.8rem; position: absolute; top: 10px">Chú ý: tránh chụp ảnh mờ, thiếu góc, chói sáng</p>
                    <img src="${(__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront}" style="height: 70%;" />
                    `,
                    css: Object.assign({
                        position: "absolute",
                        top: "55%",
                        width: "80%",
                        maxWidth: "300px",
                        height: "23%",                    
                        transform: "translateX(-50%)",
                        left: "50%",
                        position: "absolute",                    
                        display: "flex",
                        justifyContent: "center",
                        alignItems: "center"
                    }, __options.style.guideBoxStyle)
                }).appendTo(__wrapper);
            } 
            else {
                guide = jQuery('<div/>', {
                    html: 
                    `
                    <p style="font-size: 0.8rem; margin: 10px">Chú ý: tránh chụp ảnh mờ, thiếu góc, chói sáng</p>
                    <img src="${(__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront}" style="height: 70%; margin: 10px" />
                    `,
                    css: Object.assign({
                        position: "absolute",
                        top: "55%",
                        width: "80%",
                        maxWidth: "300px",
                        height: "23%",                    
                        transform: "translateX(-50%)",
                        left: "50%",
                        position: "absolute",                    
                        display: "flex",
                        justifyContent: "center",
                        alignItems: "center"
                    }, __options.style.guideBoxStyle)
                }).appendTo(__wrapper);
            }        

            takeSnapshotForWebrtc = jQuery('<div/>', {
                html: `<img style="width: ${Math.min(65, 65 * jQuery(__wrapper).height() / 870, 65 * jQuery(__wrapper).width() / 375) * 40 / 65}px" src="${__options.style.photos.snapshotButtonIcon}"/>`,
                css: Object.assign({
                        width: Math.min(65, 65 * jQuery(__wrapper).height() / 870, 65 * jQuery(__wrapper).width() / 375),
                        height: Math.min(65, 65 * jQuery(__wrapper).height() / 870, 65 * jQuery(__wrapper).width() / 375),                    
                        position: "absolute",
                        bottom: "8%",
                        transform: "translateX(-50%)",
                        left: "50%",        
                        borderRadius: "100%",                                        
                    }, __options.style.snapshotButtonStyle
                ),
                on: {
                    click: function () {
                        canvas.get(0).width = webcam.get(0).videoWidth;
                        canvas.get(0).height = webcam.get(0).videoHeight;
                        canvas.get(0).getContext('2d').drawImage(webcam.get(0), 0, 0, canvas.get(0).width, canvas.get(0).height);

                        webcamWrap.css({
                            display: 'none'
                        });

                        canvas.css({
                            display: 'block'
                        });

                        takeSnapshotForWebrtc.css({
                            display: 'none'
                        });                        
                        
                        loadingBox.hide();

                        guide.css({
                            display: "none"
                        })                        

                        nextButton.css({
                            "display": "flex",
                            "pointerEvents": "auto"
                        });
                        
                        tryAgainButton.css({
                            "display": "flex",
                            "pointerEvents": "auto"
                        });
                        
                    }
                }
            }).appendTo(__wrapper);

            navigator.mediaDevices.getUserMedia({
                video: {
                    // width: 640,
                    // height: 480,
                    width: { ideal: __options.using_mobile ? 1080 : 1920 },
                    height: { ideal: __options.using_mobile ? 1920: 1080 },
                    // width: __options.using_mobile ? 480 : 640,
                    // height: __options.using_mobile ? 640 : 480,
                    facingMode: 'environment'
                },
                audio: false
            }).then(function (stream) {
                takeSnapshotForWebrtc.css({
                    display: 'flex'
                });

                webcam.get(0).srcObject = stream;
                webcam.get(0).play();

                let stream_settings = stream.getVideoTracks()[0].getSettings();

                // actual width & height of the camera video
                let stream_width = stream_settings.width;
                let stream_height = stream_settings.height;
                
                if (webcamHeight * stream_width / stream_height > jQuery(__wrapper).width()) {
                    // webcam falls to width=100%
                    webcam_actual_height = jQuery(__wrapper).width() * stream_height / stream_width;

                    webcamWrap.css({
                        height: webcam_actual_height
                    });
                    
                    webcam.css({
                        height: webcam_actual_height
                    });
                    canvas.css({
                        height: webcam_actual_height
                    });

                }
                else {
                    webcam_actual_height = webcamHeight;
                }
                console.log(stream_width, stream_height);

                jQuery('<img/>', {
                    src: __options.style.photos.cameraFrameLarge,
                    css: {
                        height: webcam_actual_height * 0.9,
                        width: webcam_actual_height * 0.9 * 280 / 180,                    
                        position: "absolute",
                        background: "rgba(2, 253, 174, 0.4)",
                        borderRadius: "16px"
                    }
                }).appendTo(webcamWrap);
                
                jQuery('<img/>', {
                    src: __options.style.photos.cameraFrameSmall,
                    css: {
                        height: webcam_actual_height * 0.2,
                        position: "absolute"
                    }
                }).appendTo(webcamWrap);
                    
            }).catch(function (err) {
                console.log(err);
            })
        }                        

        var nextButton = jQuery('<div/>', {
            html: '<p style="font-weight: 600">Xác nhận</p>',
            type: "button",
            css: Object.assign({
                position: "absolute",
                width: "96px",
                height: "44px",
                right: "50%",
                transform: "translateX(150%)",
                top: "60%"                
            }, __options.style.nextButtonStyle),
            on: {
                click: function () {
                    var self = this;
                    jQuery(self)[0].style.pointerEvents = 'none';
                    tryAgainButton[0].style.pointerEvents = 'none';

                    if (__uploadType == "UPLOAD") {
                        inputFile.prop("disabled", true);
                    }

                    loadingBox.show();
                    
                    var formData = new FormData();
                    // var newFormData = new FormData();

                    if (__uploadType === 'UPLOAD') {
                        formData.append(side != "qr" ? 'image' : "image_file", inputFile.get(0).files[0]);
                        // if (side == "front") newFormData.append("image_file", inputFile.get(0).files[0]);                        
                    } else {
                        canvas.get(0).toBlob(function (blob) {
                            formData.append(side != "qr" ? 'image' : "image_file", blob, 'id_'  + side + '.jpg');
                            // if (side == "front") newFormData.append("image_file", blob, 'id_'  + side + '.jpg');
                        }, 'image/jpeg', 0.95);
                    }
                    
                    if (side == "selfie") {
                        formData.append("call_decision", true)
                    }

                    setTimeout(function () {
                        if (side != "qr") {
                            if (side == "front") {
                                console.log("basepath", __options.basepath);
                                axios.post(__options.basepath +  '/face-search-demo', 
                                    formData, {
                                        headers: {
                                            "Authorization": __options.token
                                        }
                                    }
                                ).then(function (response) {
                                    console.log("face search", response);
                                    localStorage.setItem("faceSearchData", JSON.stringify(response.data.image_data));
                                }).catch(function (error) {
                                    console.log(error);                                    
                                    
                                    if (error.response && error.response.status === 429) {
                                        localStorage.setItem("faceSearchData", 'API đang gọi quá tần suất cho phép, vui lòng thử lại sau ít phút.');
                                    } else if (error.response && error.response.status === 401) {
                                        localStorage.setItem("faceSearchData", 'Vui lòng điền token để xem thông tin này');
                                    } else {
                                        localStorage.setItem("faceSearchData", 'API đang gặp lỗi, vui lòng thử lại sau ít phút.');
                                    }
                                })
                            }

                            axios.post(__options.host + (side == "selfie" ? '/api/kyc/check-selfie' : __sessionPlan == "PLAN_PASSPORT_BASIC" ? '/api/kyc/check-' + side : '/api/kyc/scan-' + side), formData, {
                                headers: {
                                    'Authorization': localStorage.getItem('session_token')
                                }
                            }).then(function (response) {
                                
                                console.log(response.data);
                                if (response.data.error.code === 0) {
                                    if (__uploadType == "WEBRTC") {
                                        webcam.get(0).srcObject.getTracks().forEach(function(track) {
                                            track.stop();
                                        });
                                    }
                                    
                                    if (side == "selfie") {
                                        localStorage.setItem(side, JSON.stringify(response.data));                                
                                    }
                                    else {
                                        localStorage.setItem(`id_${side}`, JSON.stringify(response.data));                                
                                    }

                                    if (side == "front") {
                                        if (__sessionPlan != "PLAN_PASSPORT_BASIC") {
                                            uploadId("back");
                                        }
                                        else {
                                            if (__uploadType == "UPLOAD") {
                                                uploadId("selfie");
                                            }                
                                            else {
                                                liveness();
                                            }    
                                        }
                                    }
                                    else if (side == "back") {                    
                                        if (__uploadType == "UPLOAD") {
                                            uploadId("selfie");
                                        }                
                                        else {
                                            liveness();
                                        }
                                    }
                                    else {                                        
                                        __getDataUrl(inputFile.get(0).files[0]);
                                        __confirmResults();
                                    }
                                } 
                                else if (side == "selfie" && response.data.error.code == 21) {
                                    __getDataUrl(inputFile.get(0).files[0]);
                                    __confirmResults();
                                }
                                else {
                                    throw new Error(response.data.error.code);
                                }
                            }).catch(function (error) {
                                console.log(error);
                                loadingBox.hide();
                                
                                if (__uploadType === 'UPLOAD' && !inputFile.get(0).files[0]) {
                                    __showError('Ảnh CCCD / CMND mặt ' + side == "front" ? "trước" : "sau" + ' là bắt buộc.');
                                } else if (error.response && error.response.status === 401) {
                                    __showError('Phiên làm việc đã bị huỷ. Vui lòng tạo phiên làm việc mới.', initSession);
                                } else {
                                    console.log(__getErrorMessage(error.message));
                                    // tryAgainButton.click();
                                    if (__uploadType == "WEBRTC") {
                                        __showError(__getErrorMessage(error.message), () => tryAgainButton.click());
                                    }
                                    else {
                                        __showError(__getErrorMessage(error.message), () => inputBtn.click());
                                    }
                                }
                            }).finally(function () {
                                // jQuery(self).prop('disabled', false);
                                if (__uploadType == "UPLOAD") {
                                    inputFile.prop("disabled", false);
                                }
                                if (side != "selfie") {
                                    loadingBox.hide();
                                }
                                
                            });                            
                        }
                        else if (side == "qr") {

                            axios.post(__options.host + "/qr-code", formData).then(function (response) {
                                
                                console.log(response.data);
                                if (response.data.error.code === 0) {
                                    if (__uploadType == "WEBRTC") {
                                        webcam.get(0).srcObject.getTracks().forEach(function(track) {
                                            track.stop();
                                        });
                                    }
    
                                    localStorage.setItem('qr_decode', response.data.data.decoded_text);                                
                                    uploadId("back");
                                } else {
                                    if (__uploadType == "WEBRTC") {
                                        __showError(response.data.error.message, () => tryAgainButton.click());
                                    }
                                    else {
                                        __showError(response.data.error.message, () => inputBtn.click());
                                    }
                                }
                            }).catch(function (error) {
                                console.log(error);
                                if (__uploadType === 'UPLOAD' && !inputFile.get(0).files[0]) {
                                    __showError('Ảnh QR Code là bắt buộc.');
                                } else if (error.response && error.response.status === 401) {
                                    __showError('Phiên làm việc đã bị huỷ. Vui lòng tạo phiên làm việc mới.', initSession);
                                }
                            }).finally(function () {
                                jQuery(self).prop('disabled', false);
                                loadingBox.hide();
                                
                            });
                        }                        
                    }, 300);
                }
            }
        }).appendTo(__wrapper).hide();
        
        var tryAgainButton = jQuery('<div/>', {
            html: `<p style="font-weight: 600">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} lại</p>`,
            css: Object.assign({
                position: "absolute",
                width: "96px",
                height: "44px",
                left: "50%",
                transform: "translateX(-150%)",
                top: "60%"                
            }, __options.style.tryAgainButtonStyle),
            on: {
                click: function () {
                    if (__uploadType == "WEBRTC") canvas.hide()
                    nextButton.hide()
                    var self = this;
                    jQuery(self).hide();

                    webcamWrap.css({
                        display: "flex"
                    })
                    guide.css({
                        display: "flex"
                    })
                    takeSnapshotForWebrtc.css({
                        display: "flex"
                    })

                }
            }
        }).appendTo(__wrapper).hide();

        var loadingBox = jQuery('<div/>', {
            html: `<img style="height: 60px;" src="${__options.style.photos.loading}" />`,
            css: Object.assign({
                position: "absolute",               
                width: "100%", 
                bottom: "15%",
                textAlign: "center",
                display: "none"                
            }, {})            
        }).appendTo(__wrapper).hide();
        
    };

    var __confirmResults = function() {
        axios.get(__options.host + "/api/kyc/get-result", {
            headers: {
                'Authorization': localStorage.getItem('session_token')
            }
        }).then(function (response) {
            
            console.log(response.data);
            localStorage.setItem("qr_decode", JSON.stringify(response.data.data.qr_code));
            localStorage.setItem("mrz_decode", JSON.stringify(response.data.data.mrz_data));
            jQuery(__options.wrap_id).html(null);
            __wrapper = jQuery("<div/>", {
                css: {
                    height: "100%",
                    minHeight: 500
                }
            }).appendTo(__options.wrap_id);

            overflow_wrap = jQuery("<div/>", {
                css: {
                    position: "absolute",
                    top: 0,
                    width: "100%",
                    minHeight: "100%"
                }
            }
            ).appendTo(__wrapper)

            footer = jQuery("<img/>", {
                src: __options.style.photos.footer,
                css: {
                    position: "absolute",
                    bottom: 0,
                    width: "100%",
                    left: 0
                }
            }).appendTo(overflow_wrap);  
            
            var header = jQuery(
                `
                <div style="width: 80%; position: absolute; top: 5%; 
                    left: 50%; -webkit-transform: translateX(-50%);
                    transform: translateX(-50%); height: 20px">
                    <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">Xác nhận thông tin</p>                
                </div>
                `
            ).appendTo(overflow_wrap);
            
            // var backBtn = jQuery("<span/>", {
            //     html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`,
            //     css: {
            //         float: "left",
            //         cursor: "pointer",
            //         height: "20px",
            //         marginTop: "-20px",
            //         width: "20px",
            //         backgroundColor: __options.style.headlineButtonStyle.backgroundColor,
            //         borderRadius: "100%"
            //     },
            //     on: {
            //         click: () =>  backToUploadID("selfie")
            //     }
            // }).appendTo(header)

            results_wrap = jQuery("<div/>", {
                css: {
                    "position": "relative",
                    "width": "100%",
                    "marginTop": "5%",                  
                    "marginBottom": "20%"
                }
            }).appendTo(overflow_wrap);

            results = jQuery("<div/>", {
                css: {
                    "position": "relative",
                    "maxWidth": 500,
                    "padding": 0,
                    "margin": "25% auto"                                           
                }
            }).appendTo(results_wrap);
    
            var isFirefox = typeof InstallTrigger !== 'undefined';
            if (!isFirefox) {
                jQuery('<div/>', {            
                    css: {
                        height: '100%',
                        position: "absolute",
                        top: "0",
                        width: "65%",
                        left: "50%",
                        transform: "translateX(-50%)",
                        background: "rgba(2, 253, 174, 0.15)",
                        border: "none"
                        // border: "1px solid #02FDAE",
                        // borderBottom: "none",
                        // borderTop: "none"
                    }
                }).appendTo(results);
        
                jQuery('<div/>', {            
                    css: {
                        height: '100%',
                        position: "absolute",
                        top: "0",
                        width: "60%",
                        left: "50%",
                        transform: "translateX(-50%)",                    
                        border: "1px solid rgb(2, 253, 174, 0.39)",
                        borderBottom: "none",
                        borderTop: "none"
                    }
                }).appendTo(results);
        
        
                jQuery('<div/>', {            
                    css: {
                        height: '100%',
                        position: "absolute",
                        top: "0",
                        width: "70%",
                        left: "50%",
                        transform: "translateX(-50%)",
                        border: "1px solid rgb(2, 253, 174, 0.39)",
                        borderBottom: "none",
                        borderTop: "none"
                    }
                }).appendTo(results);
            }
            
            var idData = response.data.data.fields;
            jQuery('<div/>', {
                id: 'personal_information',
                html: 
                    __sessionPlan != "PLAN_PASSPORT_BASIC" ? (
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div>
                            <input class="cf-input" type="text" id="cf-id_number" value="${idData.id_number}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div>
                            <input class="cf-input" type="text" id="cf-name" value="${idData.name}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div>
                            <input class="cf-input" type="text" id="cf-dob" value="${idData.birthday}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div>
                            <input class="cf-input" type="text" id="cf-gender" value="${idData.gender}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Quê quán</div>
                            <input class="cf-input" type="text" id="cf-home" value="${idData.home}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Địa chỉ</div>
                            <input class="cf-input" type="text" id="cf-resident" value="${idData.resident}"/>
                        </div>` +
                        (idData.doi ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div>
                            <input class="cf-input" type="text" id="cf-doi" value="${idData.doi}"/>
                        </div>` : '') +
                        
                        (idData.doe ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div>
                            <input class="cf-input" type="text" id="cf-doe" value="${idData.doe}"/>
                        </div>` : '') +
                        
                        (idData.features ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Đặc điểm nhận dạng</div>
                            <input class="cf-input" type="text" id="cf-features" value="${idData.features}"/>
                        </div>` : '') +                
                        
                        (idData.poi ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div>
                            <input class="cf-input" type="text" id="cf-poi" value="${idData.poi}"/>
                        </div>` : '') +
                        
                        (idData.religion ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Tôn giáo</div>
                            <input class="cf-input" type="text" id="cf-religion" value="${idData.religion}"/>
                        </div>` : '') +
                        (idData.ethnicity ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Dân tộc</div>
                            <input class="cf-input" type="text" id="cf-ethnicity" value="${idData.ethnicity}"/>
                        </div>` : '')
                    ) : (
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div>
                            <input class="cf-input" type="text" id="cf-id_number" value="${idData.id_number}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Passport ID</div>
                            <input class="cf-input" type="text" id="cf-pp_number" value="${idData.pp_number}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div>
                            <input class="cf-input" type="text" id="cf-name" value="${idData.name}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div>
                            <input class="cf-input" type="text" id="cf-dob" value="${idData.dob}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div>
                            <input class="cf-input" type="text" id="cf-gender" value="${idData.gender}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Quốc tịch</div>
                            <input class="cf-input" type="text" id="cf-nationality" value="${idData.nationality}"/>
                        </div>` +
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi sinh</div>
                            <input class="cf-input" type="text" id="cf-pob" value="${idData.pob}"/>
                        </div>` +
                        (idData.doi ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div>
                            <input class="cf-input" type="text" id="cf-doi" value="${idData.doi}"/>
                        </div>` : '') +
                        
                        (idData.doe ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div>
                            <input class="cf-input" type="text" id="cf-doe" value="${idData.doe}"/>
                        </div>` : '') +                        
                        
                        (idData.poi ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div>
                            <input class="cf-input" type="text" id="cf-poi" value="${idData.poi}"/>
                        </div>` : '') +

                        (idData.type ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Loại</div>
                            <input class="cf-input" type="text" id="cf-type" value="${idData.type}"/>
                        </div>` : '') +
                        
                        (idData.code ?
                        `<div>
                            <div style="padding: 5px 0; width: 50%; display: inline-block">Mã số</div>
                            <input class="cf-input" type="text" id="cf-code" value="${idData.code}"/>
                        </div>` : '')
                    )

                
                ,                     
                css: {                
                    textAlign: 'left',
                    background: "rgba(255, 255, 255, 0.2)",
                    border: "1px solid #02FDAE",
                    boxSizing: "border-box",
                    boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)",
                    backdropFilter: "blur(24px)",
                    borderRadius: "19px",
                    padding: "5%",
                    width: "80%",
                    margin: "0 auto",
                    color: __options.style.textColor,
                    fontSize: "0.8rem"
                }
            }).appendTo(results);
            
            var loadingBox = jQuery('<div/>', {
                html: `<img style="height: 60px;" src="${__options.style.photos.loading}" />`,
                css: Object.assign({
                    position: "absolute",               
                    width: "100%", 
                    bottom: "-15%",
                    textAlign: "center",
                    display: "none"                
                }, {})            
            }).appendTo(results).hide();
            
            var nextButton = jQuery('<div/>', {
                html: '<p style="font-weight: 600">Xác nhận</p>',
                type: "button",
                css: Object.assign({
                    position: "absolute",
                    width: "96px",
                    height: "44px",
                    left: "50%",
                    transform: "translateX(-50%)",
                    bottom: "-15%"                
                }, __options.style.nextButtonStyle),
                on: {
                    click: function() {
                        var self = this;
                        jQuery(self).hide();
                        loadingBox.show();
                        
                        if (__sessionPlan != "PLAN_PASSPORT_BASIC") {
                            idData.id_number = jQuery("#cf-id_number").val();
                            idData.name = jQuery("#cf-name").val();
                            idData.birthday = jQuery("#cf-dob").val();
                            idData.gender = jQuery("#cf-gender").val();
                            idData.home = jQuery("#cf-home").val();
                            idData.resident = jQuery("#cf-resident").val();
                            idData.doi = jQuery("#cf-doi").val();
                            idData.doe = jQuery("#cf-doe").val();
                            idData.features = jQuery("#cf-features").val();
                            idData.poi = jQuery("#cf-poi").val();
                            idData.religion = jQuery("#cf-religion").val();
                            idData.ethnicity = jQuery("#cf-ethnicity").val();
                        } else {
                            idData.id_number = jQuery("#cf-id_number").val();
                            idData.pp_number = jQuery("#cf-pp_number").val();
                            idData.name = jQuery("#cf-name").val();
                            idData.dob = jQuery("#cf-dob").val();
                            idData.gender = jQuery("#cf-gender").val();
                            idData.nationality = jQuery("#cf-nationality").val();
                            idData.doi = jQuery("#cf-doi").val();
                            idData.doe = jQuery("#cf-doe").val();
                            idData.pob = jQuery("#cf-pob").val();
                            idData.poi = jQuery("#cf-poi").val();
                            idData.code = jQuery("#cf-code").val();
                            idData.type = jQuery("#cf-type").val();

                        }

                        axios.post(__options.host + "/api/kyc/confirm?get_full_result=true", JSON.stringify(
                            idData
                        ), {
                            headers: {
                                'Authorization': localStorage.getItem('session_token'),
                                "Content-Type": "application/json"
                            }
                        }).then(function (response) {
                            console.log(response.data);
                            localStorage.setItem("antifraud", JSON.stringify(response.data.antifraud_data));
                            localStorage.setItem("selfie", JSON.stringify(response.data.selfie_data));
                            localStorage.setItem("decision", response.data.decision);
                            localStorage.setItem("decision_details", JSON.stringify(response.data.decision_detail));
                            localStorage.setItem("verify", JSON.stringify(response.data.verify_data));
                            localStorage.setItem("ocr_data", JSON.stringify(response.data.recorrect_data));                            
                            renderResult();
                        }).catch(function (error) {
                            console.log(error);
                            if (error.response && error.response.status === 400) {
                                console.log(error.response.data);
                                if (error.response.data.data)
                                    __showError(error.response.data.data);
                                else
                                    __showError("Lỗi hệ thống. Vui lòng thử lại.", __confirmResults);
                            }
                            else if (error.response && error.response.status === 504) {
                                __showWarning('Vẫn đang trong quá trình xử lý, vui lòng thử lại sau vài giây.', initSession);
                            }
                            else {
                                __showError("Lỗi hệ thống. Vui lòng thử lại.", __confirmResults);
                            }
                        })
                        .finally(function () {
                            jQuery(self).show();
                            loadingBox.hide();            
                        });
                    }
                }
            }).appendTo(results);                    
            
        }).catch(function (error) {
            console.log(error);
            if (error.response && error.response.status === 401) {
                __showError('Phiên làm việc đã bị huỷ. Vui lòng tạo phiên làm việc mới.', initSession);
            }
            else if (error.response && error.response.status === 504) {
                __showWarning('Vẫn đang trong quá trình xử lý, vui lòng thử lại sau vài giây.', __confirmResults);
            }
            else {
                __showError("Lỗi hệ thống. Vui lòng thử lại.", __confirmResults);
            }
        })
    }

    var initSession = function () {
        __clearLocalStorage();        
        __clearLayout();

        var loadingBox = jQuery('<div/>', {
            html: `<img style="height: 60px;" src="${__options.style.photos.loading}" />`,
            css: Object.assign({
                position: "absolute",               
                width: "100%", 
                top: "50%",
                transform: "translateY(-50%)",
                textAlign: "center",
            }, {})            
        }).appendTo(__options.wrap_id);

        jQuery(__options.wrap_id).css({
            color: __options.style.textColor,
            overflowY: "scroll",
        })

        var css = `${__options.wrap_id}::-webkit-scrollbar{ display: none}`;
        var style = document.createElement('style');
        if (style.styleSheet) {
            style.styleSheet.cssText = css;
        } else {
            style.appendChild(document.createTextNode(css));
        }
        document.getElementsByTagName('head')[0].appendChild(style);

        setTimeout(() => {
            getSessionData = new Promise(resolve => {
                resolve(__options.app_authorization());
            });

            getSessionData.then((response) => {
                localStorage.setItem("session_token", response.session_id);
                __sessionPlan = response.session_plan;
                __uploadType = response.upload_type;
                __allowFullResults = response.allow_sdk_full_results;
                uploadId("front");
                // liveness();
            }).catch((error) => {
                if (error.response && error.response.status != 200) {
                    __showError("Hệ thống đang nhiều người dùng, vui lòng thử lại sau ít phút.", () => window.location.reload());
                }
                else {
                    console.log(error);
                    __showError("Có lỗi xảy ra :(", () => window.location.reload());
                }
            });
        }, 1000);
    };

    var backToUploadID = function (side) {
        try {
            __stop(true);
        }
        catch (err) {
            console.error(err)
        }
        setTimeout(() => uploadId(side), 1000);
    }

    var init = function (options) {
            if (!window.jQuery) {
                console.error('jQuery plugin did not load. Please import jQuery plugin to use ekyc sdk.');
            } else {
                console.log('jQuery plugin loaded.');

                __options = Object.assign({}, {}, options);

                jQuery("body").append(`<script src="https://cdn.jsdelivr.net/npm/qr-scanner@1.3.0/qr-scanner.umd.min.js" integrity="sha256-9MELwMQTIue1iGGeA6c2/4X62FGsTxBEScdDoPNnNaQ=" crossorigin="anonymous"></script>`);

                if (__options.app_authorization) {
                    // add other plugins
                    jQuery('body').append('<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.26.0/axios.min.js"></script>');       
                    
                    if (__options.handle_result === 'socket') {
                        jQuery('body').append('<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>');
                    }
                    
                    if (__options.sweetalert2_install) {
                        jQuery('body').append('<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>');
                    }
                    // render
                    initSession();
                } else {
                    console.log('initSessionFunction is missing.');
                }
            }
    };

    return {
        init: init
    };
})();