Proyectos de Subversion Moodle

Rev

Autoría | Ultima modificación | Ver Log |

{"version":3,"file":"async_backup.min.js","sources":["../src/async_backup.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * This module updates the UI during an asynchronous\n * backup or restore process.\n *\n * @module     core_backup/async_backup\n * @copyright  2018 Matt Porritt <mattp@catalyst-au.net>\n * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since      3.7\n */\ndefine(['jquery', 'core/ajax', 'core/str', 'core/notification', 'core/templates'],\n        function($, ajax, Str, notification, Templates) {\n\n    /**\n     * Module level constants.\n     *\n     * Using var instead of const as ES6 isn't fully supported yet.\n     */\n    var STATUS_EXECUTING = 800;\n    var STATUS_FINISHED_ERR = 900;\n    var STATUS_FINISHED_OK = 1000;\n\n    /**\n     * Module level variables.\n     */\n    var Asyncbackup = {};\n    var checkdelayoriginal = 15000; // This is the default time to use.\n    var checkdelay = 15000; // How often we should check for progress updates.\n    var checkdelaymultipler = 1.5; // If a request fails this multiplier will be used to increase the checkdelay value\n    var backupid; //  The backup id to get the progress for.\n    var contextid; //  The course this backup progress is for.\n    var restoreurl; //  The URL to view course restores.\n    var typeid; //  The type of operation backup or restore.\n    var backupintervalid; //  The id of the setInterval function.\n    var allbackupintervalid; //  The id of the setInterval function.\n    var allcopyintervalid; //  The id of the setInterval function.\n    var timeout = 2000; // Timeout for ajax requests.\n\n    /**\n     * Helper function to update UI components.\n     *\n     * @param {string} backupid The id to match elements on.\n     * @param {string} type The type of operation, backup or restore.\n     * @param {number} percentage The completion percentage to apply.\n     */\n    function updateElement(backupid, type, percentage) {\n        var percentagewidth = Math.round(percentage) + '%';\n        var elementbar = document.querySelectorAll(\"[data-\" + type + \"id=\" + CSS.escape(backupid) + \"]\")[0];\n        var percentagetext = percentage.toFixed(2) + '%';\n\n        // Set progress bar percentage indicators\n        elementbar.setAttribute('aria-valuenow', percentagewidth);\n        elementbar.style.width = percentagewidth;\n        elementbar.innerHTML = percentagetext;\n    }\n\n    /**\n     * Updates the interval we use to check for backup progress.\n     *\n     * @param {Number} intervalid The id of the interval\n     * @param {Function} callback The function to use in setInterval\n     * @param {Number} value The specified interval (in milliseconds)\n     * @returns {Number}\n     */\n    function updateInterval(intervalid, callback, value) {\n        clearInterval(intervalid);\n        return setInterval(callback, value);\n    }\n\n    /**\n     * Update backup table row when an async backup completes.\n     *\n     * @param {string} backupid The id to match elements on.\n     */\n    function updateBackupTableRow(backupid) {\n        var statuscell = $('#' + backupid + '_bar').parent().parent();\n        var tablerow = statuscell.parent();\n        var cellsiblings = statuscell.siblings();\n        var timecell = cellsiblings[1];\n        var timevalue = $(timecell).text();\n        var filenamecell = cellsiblings[0];\n        var filename = $(filenamecell).text();\n\n        ajax.call([{\n            // Get the table data via webservice.\n            methodname: 'core_backup_get_async_backup_links_backup',\n            args: {\n                'filename': filename,\n                'contextid': contextid,\n                'backupid': backupid\n            },\n        }])[0].done(function(response) {\n            // We have the data now update the UI.\n            var context = {\n                    filename: filename,\n                    time: timevalue,\n                    size: response.filesize,\n                    fileurl: response.fileurl,\n                    restoreurl: response.restoreurl\n                    };\n\n            Templates.render('core/async_backup_progress_row', context).then(function(html, js) {\n                Templates.replaceNodeContents(tablerow, html, js);\n                return;\n            }).fail(function() {\n                notification.exception(new Error('Failed to load table row'));\n                return;\n            });\n        });\n    }\n\n    /**\n     * Update restore table row when an async restore completes.\n     *\n     * @param {string} backupid The id to match elements on.\n     */\n    function updateRestoreTableRow(backupid) {\n        var statuscell = $('#' + backupid + '_bar').parent().parent();\n        var tablerow = statuscell.parent();\n        var cellsiblings = statuscell.siblings();\n        var coursecell = cellsiblings[0];\n        var timecell = cellsiblings[1];\n        var timevalue = $(timecell).text();\n\n        ajax.call([{\n            // Get the table data via webservice.\n            methodname: 'core_backup_get_async_backup_links_restore',\n            args: {\n                'backupid': backupid,\n                'contextid': contextid\n            },\n        }])[0].done(function(response) {\n         // We have the data now update the UI.\n            var resourcename = $(coursecell).text();\n            var context = {\n                    resourcename: resourcename,\n                    restoreurl: response.restoreurl,\n                    time: timevalue\n                    };\n\n            Templates.render('core/async_restore_progress_row', context).then(function(html, js) {\n                Templates.replaceNodeContents(tablerow, html, js);\n                return;\n            }).fail(function() {\n                notification.exception(new Error('Failed to load table row'));\n                return;\n            });\n        });\n    }\n\n    /**\n     * Update copy table row when an course copy completes.\n     *\n     * @param {string} backupid The id to match elements on.\n     */\n    function updateCopyTableRow(backupid) {\n        var elementbar = document.querySelectorAll(\"[data-restoreid=\" + CSS.escape(backupid) + \"]\")[0];\n        var restorecourse = elementbar.closest('tr').children[1];\n        var coursename = restorecourse.innerHTML;\n        var courselink = document.createElement('a');\n        var elementbarparent = elementbar.closest('td');\n        var operation = elementbarparent.previousElementSibling;\n\n        // Replace the prgress bar.\n        Str.get_string('complete').then(function(content) {\n            operation.innerHTML = content;\n            return;\n        }).catch(function() {\n            notification.exception(new Error('Failed to load string: complete'));\n            return;\n        });\n\n        Templates.render('core/async_copy_complete_cell', {}).then(function(html, js) {\n            Templates.replaceNodeContents(elementbarparent, html, js);\n            return;\n        }).fail(function() {\n            notification.exception(new Error('Failed to load table cell'));\n            return;\n        });\n\n        // Update the destination course name to a link to that course.\n        ajax.call([{\n            methodname: 'core_backup_get_async_backup_links_restore',\n            args: {\n                'backupid': backupid,\n                'contextid': 0\n            },\n        }])[0].done(function(response) {\n            courselink.setAttribute('href', response.restoreurl);\n            courselink.innerHTML = coursename;\n            restorecourse.innerHTML = null;\n            restorecourse.appendChild(courselink);\n\n            return;\n        }).fail(function() {\n            notification.exception(new Error('Failed to update table row'));\n            return;\n        });\n    }\n\n    /**\n     * Update the Moodle user interface with the progress of\n     * the backup process.\n     *\n     * @param {object} progress The progress and status of the process.\n     */\n    function updateProgress(progress) {\n        var percentage = progress.progress * 100;\n        var type = 'backup';\n        var elementbar = document.querySelectorAll(\"[data-\" + type + \"id=\" + CSS.escape(backupid) + \"]\")[0];\n        var elementstatus = $('#' + backupid + '_status');\n        var elementdetail = $('#' + backupid + '_detail');\n        var elementbutton = $('#' + backupid + '_button');\n        var stringRequests;\n\n        if (progress.status == STATUS_EXECUTING) {\n            // Process is in progress.\n            // Add in progress class color to bar.\n            elementbar.classList.add('bg-success');\n\n            updateElement(backupid, type, percentage);\n\n            // Change heading.\n            var strProcessing = 'async' + typeid + 'processing';\n            Str.get_string(strProcessing, 'backup').then(function(title) {\n                elementstatus.text(title);\n                return;\n            }).catch(function() {\n                notification.exception(new Error('Failed to load string: backup ' + strProcessing));\n            });\n\n        } else if (progress.status == STATUS_FINISHED_ERR) {\n            // Process completed with error.\n\n            // Add in fail class color to bar.\n            elementbar.classList.add('bg-danger');\n\n            // Remove in progress class color to bar.\n            elementbar.classList.remove('bg-success');\n\n            updateElement(backupid, type, 100);\n\n            // Change heading and text.\n            var strStatus = 'async' + typeid + 'error';\n            var strStatusDetail = 'async' + typeid + 'errordetail';\n            stringRequests = [\n                {key: strStatus, component: 'backup'},\n                {key: strStatusDetail, component: 'backup'}\n            ];\n            Str.get_strings(stringRequests).then(function(strings) {\n                elementstatus.text(strings[0]);\n                elementdetail.text(strings[1]);\n\n                return;\n            })\n            .catch(function() {\n                notification.exception(new Error('Failed to load string'));\n                return;\n            });\n\n            $('.backup_progress').children('span').removeClass('backup_stage_current');\n            $('.backup_progress').children('span').last().addClass('backup_stage_current');\n\n            // Stop checking when we either have an error or a completion.\n            clearInterval(backupintervalid);\n\n        } else if (progress.status == STATUS_FINISHED_OK) {\n            // Process completed successfully.\n\n            // Add in progress class color to bar\n            elementbar.classList.add('bg-success');\n\n            updateElement(backupid, type, 100);\n\n            // Change heading and text\n            var strComplete = 'async' + typeid + 'complete';\n            Str.get_string(strComplete, 'backup').then(function(title) {\n                elementstatus.text(title);\n                return;\n            }).catch(function() {\n                notification.exception(new Error('Failed to load string: backup ' + strComplete));\n            });\n\n            if (typeid == 'restore') {\n                ajax.call([{\n                    // Get the table data via webservice.\n                    methodname: 'core_backup_get_async_backup_links_restore',\n                    args: {\n                        'backupid': backupid,\n                        'contextid': contextid\n                    },\n                }])[0].done(function(response) {\n                    var strDetail = 'async' + typeid + 'completedetail';\n                    var strButton = 'async' + typeid + 'completebutton';\n                    var stringRequests = [\n                        {key: strDetail, component: 'backup', param: response.restoreurl},\n                        {key: strButton, component: 'backup'}\n                    ];\n                    Str.get_strings(stringRequests).then(function(strings) {\n                        elementdetail.html(strings[0]);\n                        elementbutton.text(strings[1]);\n                        elementbutton.attr('href', response.restoreurl);\n\n                        return;\n                    })\n                    .catch(function() {\n                        notification.exception(new Error('Failed to load string'));\n                        return;\n                    });\n\n                });\n            } else {\n                var strDetail = 'async' + typeid + 'completedetail';\n                var strButton = 'async' + typeid + 'completebutton';\n                stringRequests = [\n                    {key: strDetail, component: 'backup', param: restoreurl},\n                    {key: strButton, component: 'backup'}\n                ];\n                Str.get_strings(stringRequests).then(function(strings) {\n                    elementdetail.html(strings[0]);\n                    elementbutton.text(strings[1]);\n                    elementbutton.attr('href', restoreurl);\n\n                    return;\n                })\n                .catch(function() {\n                    notification.exception(new Error('Failed to load string'));\n                    return;\n                });\n\n            }\n\n            $('.backup_progress').children('span').removeClass('backup_stage_current');\n            $('.backup_progress').children('span').last().addClass('backup_stage_current');\n\n            // Stop checking when we either have an error or a completion.\n            clearInterval(backupintervalid);\n        }\n    }\n\n    /**\n     * Update the Moodle user interface with the progress of\n     * all the pending processes for backup and restore operations.\n     *\n     * @param {object} progress The progress and status of the process.\n     */\n    function updateProgressAll(progress) {\n        progress.forEach(function(element) {\n            var percentage = element.progress * 100;\n            var backupid = element.backupid;\n            var type = element.operation;\n            var elementbar = document.querySelectorAll(\"[data-\" + type + \"id=\" + CSS.escape(backupid) + \"]\")[0];\n\n            if (element.status == STATUS_EXECUTING) {\n                // Process is in element.\n\n                // Add in element class color to bar\n                elementbar.classList.add('bg-success');\n\n                updateElement(backupid, type, percentage);\n\n            } else if (element.status == STATUS_FINISHED_ERR) {\n                // Process completed with error.\n\n                // Add in fail class color to bar\n                elementbar.classList.add('bg-danger');\n                elementbar.classList.add('complete');\n\n                // Remove in element class color to bar\n                elementbar.classList.remove('bg-success');\n\n                updateElement(backupid, type, 100);\n\n            } else if (element.status == STATUS_FINISHED_OK) {\n                // Process completed successfully.\n\n                // Add in element class color to bar\n                elementbar.classList.add('bg-success');\n                elementbar.classList.add('complete');\n\n                updateElement(backupid, type, 100);\n\n                // We have a successful backup. Update the UI with download and file details.\n                if (type == 'backup') {\n                    updateBackupTableRow(backupid);\n                } else {\n                    updateRestoreTableRow(backupid);\n                }\n\n            }\n\n        });\n    }\n\n    /**\n     * Update the Moodle user interface with the progress of\n     * all the pending processes for copy operations.\n     *\n     * @param {object} progress The progress and status of the process.\n     */\n    function updateProgressCopy(progress) {\n        progress.forEach(function(element) {\n            var percentage = element.progress * 100;\n            var backupid = element.backupid;\n            var type = element.operation;\n            var elementbar = document.querySelectorAll(\"[data-\" + type + \"id=\" + CSS.escape(backupid) + \"]\")[0];\n\n            if (type == 'restore') {\n                 let restorecell = elementbar.closest('tr').children[3];\n                 Str.get_string('restore').then(function(content) {\n                     restorecell.innerHTML = content;\n                     return;\n                 }).catch(function() {\n                     notification.exception(new Error('Failed to load string: restore'));\n                 });\n            }\n\n            if (element.status == STATUS_EXECUTING) {\n                // Process is in element.\n\n                // Add in element class color to bar\n                elementbar.classList.add('bg-success');\n\n                updateElement(backupid, type, percentage);\n\n            } else if (element.status == STATUS_FINISHED_ERR) {\n                // Process completed with error.\n\n                // Add in fail class color to bar\n                elementbar.classList.add('bg-danger');\n                elementbar.classList.add('complete');\n\n                // Remove in element class color to bar\n                elementbar.classList.remove('bg-success');\n\n                updateElement(backupid, type, 100);\n\n            } else if ((element.status == STATUS_FINISHED_OK) && (type == 'restore')) {\n                // Process completed successfully.\n\n                // Add in element class color to bar\n                elementbar.classList.add('bg-success');\n                elementbar.classList.add('complete');\n\n                updateElement(backupid, type, 100);\n\n                // We have a successful copy. Update the UI link to copied course.\n                updateCopyTableRow(backupid);\n            }\n\n        });\n    }\n\n    /**\n     * Get the progress of the backup process via ajax.\n     */\n    function getBackupProgress() {\n        ajax.call([{\n            // Get the backup progress via webservice.\n            methodname: 'core_backup_get_async_backup_progress',\n            args: {\n                'backupids': [backupid],\n                'contextid': contextid\n            },\n        }], true, true, false, timeout)[0].done(function(response) {\n            // We have the progress now update the UI.\n            updateProgress(response[0]);\n            checkdelay = checkdelayoriginal;\n            backupintervalid = updateInterval(backupintervalid, getBackupProgress, checkdelayoriginal);\n        }).fail(function() {\n            checkdelay = checkdelay * checkdelaymultipler;\n            backupintervalid = updateInterval(backupintervalid, getBackupProgress, checkdelay);\n        });\n    }\n\n    /**\n     * Get the progress of all backup processes via ajax.\n     */\n    function getAllBackupProgress() {\n        var backupids = [];\n        var progressbars = $('.progress').find('.progress-bar').not('.complete');\n\n        progressbars.each(function() {\n            backupids.push((this.id).substring(0, 32));\n        });\n\n        if (backupids.length > 0) {\n            ajax.call([{\n                // Get the backup progress via webservice.\n                methodname: 'core_backup_get_async_backup_progress',\n                args: {\n                    'backupids': backupids,\n                    'contextid': contextid\n                },\n            }], true, true, false, timeout)[0].done(function(response) {\n                updateProgressAll(response);\n                checkdelay = checkdelayoriginal;\n                allbackupintervalid = updateInterval(allbackupintervalid, getAllBackupProgress, checkdelayoriginal);\n            }).fail(function() {\n                checkdelay = checkdelay * checkdelaymultipler;\n                allbackupintervalid = updateInterval(allbackupintervalid, getAllBackupProgress, checkdelay);\n            });\n        } else {\n            clearInterval(allbackupintervalid); // No more progress bars to update, stop checking.\n        }\n    }\n\n    /**\n     * Get the progress of all copy processes via ajax.\n     */\n    function getAllCopyProgress() {\n        var copyids = [];\n        var progressbars = $('.progress').find('.progress-bar[data-operation][data-backupid][data-restoreid]').not('.complete');\n\n        progressbars.each(function() {\n            let progressvars = {\n                    'backupid': this.dataset.backupid,\n                    'restoreid': this.dataset.restoreid,\n                    'operation': this.dataset.operation,\n            };\n            copyids.push(progressvars);\n        });\n\n        if (copyids.length > 0) {\n            ajax.call([{\n                // Get the copy progress via webservice.\n                methodname: 'core_backup_get_copy_progress',\n                args: {\n                    'copies': copyids\n                },\n            }], true, true, false, timeout)[0].done(function(response) {\n                updateProgressCopy(response);\n                checkdelay = checkdelayoriginal;\n                allcopyintervalid = updateInterval(allcopyintervalid, getAllCopyProgress, checkdelayoriginal);\n            }).fail(function() {\n                checkdelay = checkdelay * checkdelaymultipler;\n                allcopyintervalid = updateInterval(allcopyintervalid, getAllCopyProgress, checkdelay);\n            });\n        } else {\n            clearInterval(allcopyintervalid); // No more progress bars to update, stop checking.\n        }\n    }\n\n    /**\n     * Get status updates for all backups.\n     *\n     * @public\n     * @param {number} context The context id.\n     */\n    Asyncbackup.asyncBackupAllStatus = function(context) {\n        contextid = context;\n        allbackupintervalid = setInterval(getAllBackupProgress, checkdelay);\n    };\n\n    /**\n     * Get status updates for all course copies.\n     *\n     * @public\n     */\n    Asyncbackup.asyncCopyAllStatus = function() {\n        allcopyintervalid = setInterval(getAllCopyProgress, checkdelay);\n    };\n\n    /**\n     * Get status updates for backup.\n     *\n     * @public\n     * @param {string} backup The backup record id.\n     * @param {number} context The context id.\n     * @param {string} restore The restore link.\n     * @param {string} type The operation type (backup or restore).\n     */\n    Asyncbackup.asyncBackupStatus = function(backup, context, restore, type) {\n        backupid = backup;\n        contextid = context;\n        restoreurl = restore;\n\n        if (type == 'backup') {\n            typeid = 'backup';\n        } else {\n            typeid = 'restore';\n        }\n\n        // Remove the links from the progress bar, no going back now.\n        $('.backup_progress').children('a').removeAttr('href');\n\n        //  Periodically check for progress updates and update the UI as required.\n        backupintervalid = setInterval(getBackupProgress, checkdelay);\n\n      };\n\n      return Asyncbackup;\n});\n"],"names":["define","$","ajax","Str","notification","Templates","backupid","contextid","restoreurl","typeid","backupintervalid","allbackupintervalid","allcopyintervalid","Asyncbackup","checkdelay","updateElement","type","percentage","percentagewidth","Math","round","elementbar","document","querySelectorAll","CSS","escape","percentagetext","toFixed","setAttribute","style","width","innerHTML","updateInterval","intervalid","callback","value","clearInterval","setInterval","updateProgressAll","progress","forEach","element","operation","status","classList","add","remove","statuscell","parent","tablerow","cellsiblings","siblings","timecell","timevalue","text","filenamecell","filename","call","methodname","args","done","response","context","time","size","filesize","fileurl","render","then","html","js","replaceNodeContents","fail","exception","Error","updateBackupTableRow","coursecell","resourcename","updateRestoreTableRow","updateProgressCopy","restorecell","closest","children","get_string","content","catch","restorecourse","coursename","courselink","createElement","elementbarparent","previousElementSibling","appendChild","updateCopyTableRow","getBackupProgress","stringRequests","elementstatus","elementdetail","elementbutton","strProcessing","title","key","component","get_strings","strings","removeClass","last","addClass","strComplete","strButton","param","attr","updateProgress","getAllBackupProgress","backupids","find","not","each","push","this","id","substring","length","getAllCopyProgress","copyids","progressvars","dataset","restoreid","asyncBackupAllStatus","asyncCopyAllStatus","asyncBackupStatus","backup","restore","removeAttr"],"mappings":";;;;;;;;;AAwBAA,kCAAO,CAAC,SAAU,YAAa,WAAY,oBAAqB,mBACxD,SAASC,EAAGC,KAAMC,IAAKC,aAAcC,eAkBrCC,SACAC,UACAC,WACAC,OACAC,iBACAC,oBACAC,kBAVAC,YAAc,GAEdC,WAAa,cAkBRC,cAAcT,SAAUU,KAAMC,gBAC/BC,gBAAkBC,KAAKC,MAAMH,YAAc,IAC3CI,WAAaC,SAASC,iBAAiB,SAAWP,KAAO,MAAQQ,IAAIC,OAAOnB,UAAY,KAAK,GAC7FoB,eAAiBT,WAAWU,QAAQ,GAAK,IAG7CN,WAAWO,aAAa,gBAAiBV,iBACzCG,WAAWQ,MAAMC,MAAQZ,gBACzBG,WAAWU,UAAYL,wBAWlBM,eAAeC,WAAYC,SAAUC,cAC1CC,cAAcH,YACPI,YAAYH,SAAUC,gBAwRxBG,kBAAkBC,UACvBA,SAASC,SAAQ,SAASC,aAClBxB,WAAgC,IAAnBwB,QAAQF,SACrBjC,SAAWmC,QAAQnC,SACnBU,KAAOyB,QAAQC,UACfrB,WAAaC,SAASC,iBAAiB,SAAWP,KAAO,MAAQQ,IAAIC,OAAOnB,UAAY,KAAK,GA7UlF,KA+UXmC,QAAQE,QAIRtB,WAAWuB,UAAUC,IAAI,cAEzB9B,cAAcT,SAAUU,KAAMC,aApVhB,KAsVPwB,QAAQE,QAIftB,WAAWuB,UAAUC,IAAI,aACzBxB,WAAWuB,UAAUC,IAAI,YAGzBxB,WAAWuB,UAAUE,OAAO,cAE5B/B,cAAcT,SAAUU,KAAM,MA/VjB,KAiWNyB,QAAQE,SAIftB,WAAWuB,UAAUC,IAAI,cACzBxB,WAAWuB,UAAUC,IAAI,YAEzB9B,cAAcT,SAAUU,KAAM,KAGlB,UAARA,cArTcV,cACtByC,WAAa9C,EAAE,IAAMK,SAAW,QAAQ0C,SAASA,SACjDC,SAAWF,WAAWC,SACtBE,aAAeH,WAAWI,WAC1BC,SAAWF,aAAa,GACxBG,UAAYpD,EAAEmD,UAAUE,OACxBC,aAAeL,aAAa,GAC5BM,SAAWvD,EAAEsD,cAAcD,OAE/BpD,KAAKuD,KAAK,CAAC,CAEPC,WAAY,4CACZC,KAAM,UACUH,mBACCjD,mBACDD,aAEhB,GAAGsD,MAAK,SAASC,cAEbC,QAAU,CACNN,SAAUA,SACVO,KAAMV,UACNW,KAAMH,SAASI,SACfC,QAASL,SAASK,QAClB1D,WAAYqD,SAASrD,YAG7BH,UAAU8D,OAAO,iCAAkCL,SAASM,MAAK,SAASC,KAAMC,IAC5EjE,UAAUkE,oBAAoBtB,SAAUoB,KAAMC,OAE/CE,MAAK,WACJpE,aAAaqE,UAAU,IAAIC,MAAM,mCAuR7BC,CAAqBrE,mBA5QNA,cACvByC,WAAa9C,EAAE,IAAMK,SAAW,QAAQ0C,SAASA,SACjDC,SAAWF,WAAWC,SACtBE,aAAeH,WAAWI,WAC1ByB,WAAa1B,aAAa,GAC1BE,SAAWF,aAAa,GACxBG,UAAYpD,EAAEmD,UAAUE,OAE5BpD,KAAKuD,KAAK,CAAC,CAEPC,WAAY,6CACZC,KAAM,UACUrD,mBACCC,cAEjB,GAAGqD,MAAK,SAASC,cAGbC,QAAU,CACNe,aAFW5E,EAAE2E,YAAYtB,OAGzB9C,WAAYqD,SAASrD,WACrBuD,KAAMV,WAGdhD,UAAU8D,OAAO,kCAAmCL,SAASM,MAAK,SAASC,KAAMC,IAC7EjE,UAAUkE,oBAAoBtB,SAAUoB,KAAMC,OAE/CE,MAAK,WACJpE,aAAaqE,UAAU,IAAIC,MAAM,mCAkP7BI,CAAsBxE,uBAc7ByE,mBAAmBxC,UACxBA,SAASC,SAAQ,SAASC,aAClBxB,WAAgC,IAAnBwB,QAAQF,SACrBjC,SAAWmC,QAAQnC,SACnBU,KAAOyB,QAAQC,UACfrB,WAAaC,SAASC,iBAAiB,SAAWP,KAAO,MAAQQ,IAAIC,OAAOnB,UAAY,KAAK,MAErF,WAARU,KAAmB,KACdgE,YAAc3D,WAAW4D,QAAQ,MAAMC,SAAS,GACpD/E,IAAIgF,WAAW,WAAWf,MAAK,SAASgB,SACpCJ,YAAYjD,UAAYqD,WAEzBC,OAAM,WACLjF,aAAaqE,UAAU,IAAIC,MAAM,sCA3Y3B,KA+YXjC,QAAQE,QAIRtB,WAAWuB,UAAUC,IAAI,cAEzB9B,cAAcT,SAAUU,KAAMC,aApZhB,KAsZPwB,QAAQE,QAIftB,WAAWuB,UAAUC,IAAI,aACzBxB,WAAWuB,UAAUC,IAAI,YAGzBxB,WAAWuB,UAAUE,OAAO,cAE5B/B,cAAcT,SAAUU,KAAM,MA/ZjB,KAiaLyB,QAAQE,QAA0C,WAAR3B,OAIlDK,WAAWuB,UAAUC,IAAI,cACzBxB,WAAWuB,UAAUC,IAAI,YAEzB9B,cAAcT,SAAUU,KAAM,cAjSdV,cACpBe,WAAaC,SAASC,iBAAiB,mBAAqBC,IAAIC,OAAOnB,UAAY,KAAK,GACxFgF,cAAgBjE,WAAW4D,QAAQ,MAAMC,SAAS,GAClDK,WAAaD,cAAcvD,UAC3ByD,WAAalE,SAASmE,cAAc,KACpCC,iBAAmBrE,WAAW4D,QAAQ,MACtCvC,UAAYgD,iBAAiBC,uBAGjCxF,IAAIgF,WAAW,YAAYf,MAAK,SAASgB,SACrC1C,UAAUX,UAAYqD,WAEvBC,OAAM,WACLjF,aAAaqE,UAAU,IAAIC,MAAM,uCAIrCrE,UAAU8D,OAAO,gCAAiC,IAAIC,MAAK,SAASC,KAAMC,IACtEjE,UAAUkE,oBAAoBmB,iBAAkBrB,KAAMC,OAEvDE,MAAK,WACJpE,aAAaqE,UAAU,IAAIC,MAAM,iCAKrCxE,KAAKuD,KAAK,CAAC,CACPC,WAAY,6CACZC,KAAM,UACUrD,mBACC,MAEjB,GAAGsD,MAAK,SAASC,UACjB2B,WAAW5D,aAAa,OAAQiC,SAASrD,YACzCgF,WAAWzD,UAAYwD,WACvBD,cAAcvD,UAAY,KAC1BuD,cAAcM,YAAYJ,eAG3BhB,MAAK,WACJpE,aAAaqE,UAAU,IAAIC,MAAM,kCA4P7BmB,CAAmBvF,uBAStBwF,oBACL5F,KAAKuD,KAAK,CAAC,CAEPC,WAAY,wCACZC,KAAM,WACW,CAACrD,oBACDC,cAEjB,GAAM,GAAM,EA5aN,KA4asB,GAAGqD,MAAK,SAASC,oBAlQ7BtB,cAOhBwD,eANA9E,WAAiC,IAApBsB,SAASA,SACtBvB,KAAO,SACPK,WAAaC,SAASC,iBAAiB,kBAA0BC,IAAIC,OAAOnB,UAAY,KAAK,GAC7F0F,cAAgB/F,EAAE,IAAMK,SAAW,WACnC2F,cAAgBhG,EAAE,IAAMK,SAAW,WACnC4F,cAAgBjG,EAAE,IAAMK,SAAW,cAlMpB,KAqMfiC,SAASI,OAA4B,CAGrCtB,WAAWuB,UAAUC,IAAI,cAEzB9B,cAAcT,SAAUU,KAAMC,gBAG1BkF,cAAgB,QAAU1F,OAAS,aACvCN,IAAIgF,WAAWgB,cAAe,UAAU/B,MAAK,SAASgC,OAClDJ,cAAc1C,KAAK8C,UAEpBf,OAAM,WACLjF,aAAaqE,UAAU,IAAIC,MAAM,iCAAmCyB,wBAGrE,GApNe,KAoNX5D,SAASI,OAIhBtB,WAAWuB,UAAUC,IAAI,aAGzBxB,WAAWuB,UAAUE,OAAO,cAE5B/B,cAAcT,SAAUU,KAAM,KAK9B+E,eAAiB,CACb,CAACM,IAHW,QAAU5F,OAAS,QAGd6F,UAAW,UAC5B,CAACD,IAHiB,QAAU5F,OAAS,cAGd6F,UAAW,WAEtCnG,IAAIoG,YAAYR,gBAAgB3B,MAAK,SAASoC,SAC1CR,cAAc1C,KAAKkD,QAAQ,IAC3BP,cAAc3C,KAAKkD,QAAQ,OAI9BnB,OAAM,WACHjF,aAAaqE,UAAU,IAAIC,MAAM,6BAIrCzE,EAAE,oBAAoBiF,SAAS,QAAQuB,YAAY,wBACnDxG,EAAE,oBAAoBiF,SAAS,QAAQwB,OAAOC,SAAS,wBAGvDvE,cAAc1B,uBAEX,GAtPc,KAsPV6B,SAASI,OAA8B,CAI9CtB,WAAWuB,UAAUC,IAAI,cAEzB9B,cAAcT,SAAUU,KAAM,SAG1B4F,YAAc,QAAUnG,OAAS,WACrCN,IAAIgF,WAAWyB,YAAa,UAAUxC,MAAK,SAASgC,OAChDJ,cAAc1C,KAAK8C,UAEpBf,OAAM,WACLjF,aAAaqE,UAAU,IAAIC,MAAM,iCAAmCkC,iBAG1D,WAAVnG,OACAP,KAAKuD,KAAK,CAAC,CAEPC,WAAY,6CACZC,KAAM,UACUrD,mBACCC,cAEjB,GAAGqD,MAAK,SAASC,cAEbgD,UAAY,QAAUpG,OAAS,iBAC/BsF,eAAiB,CACjB,CAACM,IAHW,QAAU5F,OAAS,iBAGd6F,UAAW,SAAUQ,MAAOjD,SAASrD,YACtD,CAAC6F,IAAKQ,UAAWP,UAAW,WAEhCnG,IAAIoG,YAAYR,gBAAgB3B,MAAK,SAASoC,SAC1CP,cAAc5B,KAAKmC,QAAQ,IAC3BN,cAAc5C,KAAKkD,QAAQ,IAC3BN,cAAca,KAAK,OAAQlD,SAASrD,eAIvC6E,OAAM,WACHjF,aAAaqE,UAAU,IAAIC,MAAM,iCAQzCqB,eAAiB,CACb,CAACM,IAHW,QAAU5F,OAAS,iBAGd6F,UAAW,SAAUQ,MAAOtG,YAC7C,CAAC6F,IAHW,QAAU5F,OAAS,iBAGd6F,UAAW,WAEhCnG,IAAIoG,YAAYR,gBAAgB3B,MAAK,SAASoC,SAC1CP,cAAc5B,KAAKmC,QAAQ,IAC3BN,cAAc5C,KAAKkD,QAAQ,IAC3BN,cAAca,KAAK,OAAQvG,eAI9B6E,OAAM,WACHjF,aAAaqE,UAAU,IAAIC,MAAM,8BAMzCzE,EAAE,oBAAoBiF,SAAS,QAAQuB,YAAY,wBACnDxG,EAAE,oBAAoBiF,SAAS,QAAQwB,OAAOC,SAAS,wBAGvDvE,cAAc1B,mBAkIdsG,CAAenD,SAAS,IACxB/C,WAzbiB,KA0bjBJ,iBAAmBsB,eAAetB,iBAAkBoF,kBA1bnC,SA2blBtB,MAAK,WAEJ9D,iBAAmBsB,eAAetB,iBAAkBoF,kBADpDhF,YA1bkB,iBAkcjBmG,2BACDC,UAAY,GACGjH,EAAE,aAAakH,KAAK,iBAAiBC,IAAI,aAE/CC,MAAK,WACdH,UAAUI,KAAMC,KAAKC,GAAIC,UAAU,EAAG,QAGtCP,UAAUQ,OAAS,EACnBxH,KAAKuD,KAAK,CAAC,CAEPC,WAAY,wCACZC,KAAM,WACWuD,oBACA3G,cAEjB,GAAM,GAAM,EA1cV,KA0c0B,GAAGqD,MAAK,SAASC,UAC7CvB,kBAAkBuB,UAClB/C,WAtda,KAudbH,oBAAsBqB,eAAerB,oBAAqBsG,qBAvd7C,SAwddzC,MAAK,WAEJ7D,oBAAsBqB,eAAerB,oBAAqBsG,qBAD1DnG,YAvdc,QA2dlBsB,cAAczB,8BAObgH,yBACDC,QAAU,GACK3H,EAAE,aAAakH,KAAK,gEAAgEC,IAAI,aAE9FC,MAAK,eACVQ,aAAe,UACCN,KAAKO,QAAQxH,mBACZiH,KAAKO,QAAQC,oBACbR,KAAKO,QAAQpF,WAElCkF,QAAQN,KAAKO,iBAGbD,QAAQF,OAAS,EACjBxH,KAAKuD,KAAK,CAAC,CAEPC,WAAY,gCACZC,KAAM,QACQiE,YAEd,GAAM,GAAM,EA9eV,KA8e0B,GAAGhE,MAAK,SAASC,UAC7CkB,mBAAmBlB,UACnB/C,WA1fa,KA2fbF,kBAAoBoB,eAAepB,kBAAmB+G,mBA3fzC,SA4fdnD,MAAK,WAEJ5D,kBAAoBoB,eAAepB,kBAAmB+G,mBADtD7G,YA3fc,QA+flBsB,cAAcxB,0BAUtBC,YAAYmH,qBAAuB,SAASlE,SACxCvD,UAAYuD,QACZnD,oBAAsB0B,YAAY4E,qBAAsBnG,aAQ5DD,YAAYoH,mBAAqB,WAC7BrH,kBAAoByB,YAAYsF,mBAAoB7G,aAYxDD,YAAYqH,kBAAoB,SAASC,OAAQrE,QAASsE,QAASpH,MAC/DV,SAAW6H,OACX5H,UAAYuD,QACZtD,WAAa4H,QAGT3H,OADQ,UAARO,KACS,SAEA,UAIbf,EAAE,oBAAoBiF,SAAS,KAAKmD,WAAW,QAG/C3H,iBAAmB2B,YAAYyD,kBAAmBhF,aAI7CD"}