Batch Edit

DataViews supports batch edit, which allows you to send a single request that consists of multiple actions.

<p>When CRUD is applied, DataViews communicates with the server when you edit an item.</p> <p>Sending a server request every time you edit an item is a waste of server bandwidth and performance. The more economic way is to send a request to the server once after a series of local edits.</p> <p>DataViews supports batch edit, which allows you to send a single request that consists of multiple actions.</p> <p>To apply batch editing, set <strong>dataSource.batchEdit = true</strong>. Once batch edit mode is set, update and create item actions are only applied locally. To save changes, use <strong>dataView.saveBatchEdit()</strong>. After that, <strong>dataSource.batch(params)</strong> is used to allow you to send a request, such as CRUD. To cancel batch edit and remove cached edits, use <strong>dataView.cancelBatchEdit()</strong>.</p> <p>The <strong>params</strong> contain: <strong>[Array] actions</strong>, which is the cache of all locally applied actions of create, update, and delete.</p> <p>Try using CRUD actions in the grid and then save or cancel the changes using the buttons above the grid.</p> <p><span style="color:#c7254e;font-style:italic;">This demo calls some API items from the internet, make sure your internet connection is working and runing this demo with HTTP or HTTPS protocol.</span></p>
<!DOCTYPE html> <html lang="en"> <head> <base href="/dataviewsjs/demos/en/sample/Features/Editing/BatchEdit/purejs/" /> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="keywords" content="crud" /> <meta name="description" content="DataViews supports batch edit, which allows you to send a single request that consists of multiple actions." /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Batch Edit | Features | GrapeCity DataViewsJS JavaScript Demos</title> <link href="/dataviewsjs/demos/node_modules/normalize.css/normalize.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/css/base.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/node_modules/@fortawesome/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/css/pageui.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/css/bootstrap-snippet.min.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/dataviews/gc.dataviews.core.min.css" rel="stylesheet" type="text/css" /> <link href="/dataviewsjs/demos/static/dataviews/gc.dataviews.grid.min.css" rel="stylesheet" type="text/css" /> <link href="styles.css" rel="stylesheet" type="text/css" /> <!-- Google Tag Manager --> <script> (function (w, d, s, l, i) { w[l] = w[l] || []; w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' }); var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f.parentNode.insertBefore(j, f); })(window, document, 'script', 'dataLayer', 'GTM-WT462SJ'); </script> <!-- End Google Tag Manager --> <script src="/dataviewsjs/demos/static/js/app-polyfills.min.js" type="text/javascript"></script> <script type="text/javascript"> window.process = { env: { NODE_ENV: 'production', USE_NPM: false, USE_CDN: false, SITE_ROOT: '/dataviewsjs/demos', FRAMEWORK: 'purejs', DVJS_LICENSE_KEY: 'E674186349827489#B0LYWQMpFdP3WSHlVaGdjTFtyLCxUQjdFV5MHey9kTyBnY0pkY6tWcr34caJjSPlEVlR6QpJnZEdjSj9kbkRUZChzMsRFS99mN4ZGO72yK7FXe5tmN59Eai5UM7dEVvgUeYN5MqdUTIpWTpBnSTJEWv24YwoFWr9mWEl6UNVmVMxUd5ckUQdlUNV4MDhENaV5KNNWbJtiSwFUYCVUax4GUuBjZDN7T5dWdDpFNyJjSxJkes3mUt94QrdnMK5mZORGeFZ4QyFTMmdWOWdlMmJ4ZJhTS5MmZatyZ7k5c0JXVB3mWVNke7AFRiojITJCLikjNBNjNzcjI0ICSiwSN8AjN9YjMwUTM0IicfJye35XX3JSWUVVOiojIDJCLiEjdgMlSzdXZpZVY4FGRiojIOJyebpjIkJHUiwiI9MDMykDMggDM8ATOxAjMiojI4J7QiwiIt36YukHdpNWZwFmcn9iKiojIz5GRiwiIj9WSgkHdpNUZwFmcHJiOiEmTDJCLlVnc4pjIsZXRiwiI9gDN7IDO9QzM6gTM4cjNiojIklkI1pjIEJCLi4TPn3UZuJ7cPZTW5hUMtN7MJN6aQFnT5gmd9FEZ4EETlFmW63kU8IGdiRGTJZle5UDbZJHTR34T0JzZoZmbalXQwNmM8EndEFEdSVlMiVnckFmQUJTOahmc7AzRHhlU4I4Vs3kN6lHaHR4LuhWULNIe', SJS_LICENSE_KEY: '*.grapecity.com,E613631884219496#B0qRgJHWSJ7NyBlc8BjNMRHW7g7YldTZXFTQuFnW4hVOCplVSlVV09ERlhEZuVTVKlTazE4Q6VGSw2CdWZUWSVmbjVXbrxmWFVWR8ZzQro7U84WMGdlbuVHb73kS5kjUTN4NvFVdLdXWVR4Nox6Z7UUSysEcXJEMsN6bDN4TxMDVwVmWBRzKxhkTzAXTaJmdD3CRFJTd8R4R6M5RklWa6oUaLlXMwR4R8ZUdtRWVxUUaQh6VXNDdEhlZ7FHR6QXTPJTVvkWcyZnbSdHRtZHcYF6TKN4axYGcZNjTDF7TvFTTr24VqZjVHVjcLd7QkRmdNxkI0IyUiwiI5gDOEF4QGVjI0ICSiwiMzkTO9kTOyMTM0IicfJye35XX3JSSGljQiojIDJCLiITMuYHITpEIkFWZyB7UiojIOJyebpjIkJHUiwiI4MDMyEDMgkDM8ATOxAjMiojI4J7QiwiIt36YukHdpNWZwFmcn9iKiojIz5GRiwiIj9WagkHdpNUZwFmcHJiOiEmTDJCLlVnc4pjIsZXRiwiI6kDN9EjM4gDOxMjNzEjNiojIklkIs4XZzxWYmpjIyNHZisnOiwmbBJye0ICRiwiI34TQ72kNBV6YXpXdGxGWxdHcol4MyUGUHJVbQVHRx44Sw84YxRkS4QnZadDNmhWWxV5QxFlTlZEbBJ5N8gUNQlDb7J6Kl36YHVnb4NGN92UMFdlNORFU8VDSaFlQSVlS4EHTrA5Ohh', }, }; </script> <script src="/dataviewsjs/demos/node_modules/jquery/dist/jquery.min.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/js/batchjs.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/js/pageui.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/dataviews/gc.dataviews.common.min.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/dataviews/gc.dataviews.core.min.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/dataviews/gc.dataviews.grid.min.js" type="text/javascript"></script> <script src="/dataviewsjs/demos/static/js/license.js" type="text/javascript"></script> </head> <body class="theme-default"> <!-- Google Tag Manager (noscript) --> <noscript ><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-WT462SJ" height="0" width="0" style="display: none; visibility: hidden;" ></iframe ></noscript> <!-- End Google Tag Manager (noscript) --> <noscript>You need to enable JavaScript to run this app.</noscript> <div class="main-container"> <div class="sample-options"> <div class="btn-group"> <button id="save-changes" class="btn btn-default">Save Changes</button> <button id="cancel-changes" class="btn btn-default">Cancel Changes</button> </div> </div> <div id="grid" class="grid"></div> <div id="page-nav"></div> </div> <script src="locale.js" type="text/javascript"></script> <script src="data.js" type="text/javascript"></script> <script src="app.js" type="text/javascript"></script> </body> </html>
var cols = [ { id: 'id', caption: 'Order Id', dataField: 'Transaction_Id', dataType: 'number', allowEditing: false, width: 80, }, { id: 'product', caption: 'Product', dataField: 'Product', width: 290, }, { id: 'price', caption: 'Price', dataField: 'Price', dataType: 'number', width: 60, }, { id: 'quantity', caption: 'Qty', dataField: 'Quantity', dataType: 'number', width: 55, }, { id: 'name', caption: 'Name', dataField: 'Name', width: 135, }, { id: 'country', caption: 'Country', dataField: 'Country', width: 120, }, { id: 'detail', caption: 'Detail', dataField: 'Product_Detail', width: '*', minWidth: 445, }, { id: 'editCol', width: 75, action: [ { name: 'edit', presenter: '<button class="edit-btn action-btn" data-action="edit"><span class="edit-icon"></span></button>', handler: startEditing, }, { name: 'save', presenter: '<button class="save-btn action-btn" data-action="save" style="display:none;"><span class="save-icon"></span></button>', handler: saveEdit, }, { name: 'cancel', presenter: '<button class="cancel-btn action-btn" data-action="cancel" style="display:none;"><span class="cancel-icon"></span></button>', handler: cancelEdit, }, ], }, { id: 'deleteCol', width: 50, action: [ { name: 'delete', presenter: '<button class="delete-btn action-btn" data-action="delete"><span>✖</span></button>', handler: deleteItem, }, ], }, ]; var layout = new GC.DataViews.GridLayout({ colWidth: 80, showRowHeader: true, rowHeight: 36, showColHeader: true, pageSize: 9, allowEditing: true, autoAddRowPosition: 'top', headerRow: { visible: true, height: 40, separateColumn: false, position: 'above', renderer: '\n<button id="btnAddNew" class="btn btn-sm">\n <span class="add-icon"></span>\n <span>'.concat( locale.addNew, '</span>\n</button>' ), }, }); var dataView = new GC.DataViews.DataView(document.getElementById('grid'), dataSource, cols, layout); dataView.editing.addHandler(function (args) { if ((args.status === 'endEditing' && args.isNewRow) || args.status === 'cancelEditing') { if (dataView.options.allowAutoAddRow) { dataView.options.allowAutoAddRow = false; dataView.invalidate(); } } }); function addNewRow() { if (!dataView.isEditing) { dataView.options.allowAutoAddRow = true; dataView.invalidate(); var autoRow = $('#'.concat(dataView.uid, '-autorow')); autoRow.find('[data-action="save"]').css('display', 'inline-block'); autoRow.find('[data-action="cancel"]').css('display', 'inline-block'); autoRow.find('[data-action="edit"]').css('display', 'none'); autoRow.find('[data-action="delete"]').css('display', 'none'); dataView.startEditing(0); } } document.querySelector('.main-container').addEventListener('click', function (e) { var target = e.target; while (target) { if ($(target).is('#btnAddNew')) { addNewRow(); break; } target = target.parentNode; } }); document.getElementById('save-changes').addEventListener('click', function () { dataView.saveBatchEdit(); }); document.getElementById('cancel-changes').addEventListener('click', function () { dataView.cancelBatchEdit(); }); PageUI.init(dataView.data.pageController); dataView.beforeLoadRange.addHandler(function (args) { var cachedActions = dataView.getCachedBatchActions(); if (cachedActions) { alert(locale.navError); args.cancel = true; } }); // action column handler function startEditing(args) { var hitInfo = args.hitInfo; var elementId = dataView.getRowId(hitInfo); if (!dataView.isEditing) { var row = $('#'.concat(elementId)); row.find('[data-action="save"]').css('display', 'inline-block'); row.find('[data-action="cancel"]').css('display', 'inline-block'); row.find('[data-action="edit"]').css('display', 'none'); row.find('[data-action="delete"]').css('display', 'none'); dataView.startEditing(); } } function saveEdit() { dataView.stopEditing(); } function cancelEdit() { dataView.cancelEditing(); } function deleteItem(args) { var rowId = dataView.getRowId(args.hitInfo); var dataItem = dataView.getItem(rowId); if (dataItem && dataItem.item) { var sourceIndex = dataItem.item.sourceIndex; if (sourceIndex >= 0) { dataView.data.removeDataItems(sourceIndex); } } }
var API_ROOT = ''.concat(process.env.SITE_ROOT, '/remotedata/api'); function buildRequests(actions) { var result = []; var i; var len; var action; var actionType; var dataItem; for (i = 0, len = actions.length; i < len; i++) { action = actions[i]; actionType = action.type; dataItem = action.dataItem; if (actionType === 'update') { result.push({ type: 'PUT', url: ''.concat(API_ROOT, '/records/').concat(dataItem.Transaction_Id), data: dataItem, }); } else if (actionType === 'delete') { result.push({ type: 'DELETE', url: ''.concat(API_ROOT, '/records/').concat(dataItem.Transaction_Id), }); } else if (actionType === 'create') { result.push({ type: 'POST', url: ''.concat(API_ROOT, '/records'), data: dataItem, }); } } return result; } function getRecords(start, count) { return ''.concat(API_ROOT, '/records'); } var parseBatchResponse = function parseBatchResponse(responseData) { // response of batch edit should be an array, which contains each action's response status. // each action's response should be an object, which contains success status and response information. { status: [Boolean], object: [Object] } return responseData.map(function (response) { return { status: response.status === 200 || response.status === 204, object: response.data, }; }); }; var dataSource = { loadRange: function loadRange(params) { $.ajax({ // pageSize and startPageIndex only works when paging component is referenced, if control // do find the paging component, pageIndex and pageSize will be undefined. url: getRecords(params.pageIndex === undefined ? undefined : params.pageSize * params.pageIndex, params.pageSize), crossDomain: true, success: function success(result) { var currentPageDataSource = result.m_Item2; var itemsTotalCount = result.m_Item1; params.success(currentPageDataSource, itemsTotalCount); }, error: function error(xhr, status) { params.failed(); if (status !== 'abort') { alert(locale.loadFailed); } }, }); }, batch: function batch(params) { jQuery.ajaxBatch({ url: ''.concat(API_ROOT, '/$batch'), data: buildRequests(params.actions), complete: function complete(xhr, status, data) { params.success(parseBatchResponse(data)); }, }); }, batchEdit: true, };
var locale = { saveChanges: 'Save Changes', cancelChanges: 'Cancel Changes', loadFailed: 'Failed to load data from remote web site.', navError: "Cannot navigate to another page because there are some changes which don't submit to server.", addNew: ' Add new record', };
.main-container { display: flex; flex-direction: column; width: 100%; height: 100%; overflow: auto; } .sample-options { background: #fbfbfb; box-sizing: border-box; float: right; overflow: auto; padding: 10px; flex-grow: 0; flex-shrink: 0; } .sample-options .btn { display: flex; align-items: center; justify-content: center; height: 32px; } #grid { height: calc(100% - 95px); min-height: 200px; width: 100%; flex-grow: 0; flex-shrink: 0; } .gc-header-row-cell { background-color: #eaeaea; display: flex; align-items: center; } #btnAddNew { display: flex; align-items: center; justify-content: center; border-radius: 5px; margin: 5px; } .add-icon { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7CAAAOwgEVKEqAAAAAB3RJTUUH3QsJATErA49PDwAAAgBJREFUOMut1T1IVWEYB/DfPfdKXxTRkFFD0KUhDUIotEYHl0KkoKlF+qBIoqGGloZoq6EPpaAiCGmIDDVaa4sgSYSyaIiiEEkSK4REr7flOXA63NsH9MCBw/s+z//5/r+Fjo4ONWQrdmMvmlGN8wJe4QEe4WXesJADXImTOI05PMczTMf9GrRhB5bgAi7hewpQyoCtQy/24V4oj6gt28PpOWxDDyazgKvRhz04hluYV19GcABPcDlKcRAzKWBP1Oswbvo7mcd1LOAGRnG+WC6Xm3EH93E204BUVmEX1mMqALIyhs04hKEEneHtIio1ItmCAdzG2hr3lbCdR2eCLjyNkOulVox6/6ijMxoYXQmaYjSyqa7AJjRGqgUk2IgN8TVk9KuB0VQKxS85j+3RnG9YHg6WRepVfEI33mZsppEkoVDxn6QUgI2588fYidnYiruRxX5MhM7nnM0aLJYwjtaoU1rHWbyL/4k4X8SHGkDpjrdhPMFgzFlLnSwaoiQLWFpHpyUwBhMMh9GpGI+8vI797q4TXTFsGzBcLJfLU9HpE/iIFzmDObyPu4UagEdwJohiIN3l3gi7Lxr1J3JIS3E0yGEAV0VkMIPjeIhr6A+K8hv66seV4IAefM3z4WTUaSy4rj1HsJXY5dYYpWKQyS8EW/iHJ6AaGaVPwBDe5A1/AgojgwuRXC6BAAAAAElFTkSuQmCC"); background-repeat: no-repeat; border: 0; color: transparent; cursor: pointer; height: 20px; margin-right: 5px; padding: 0; width: 20px; } .edit-icon { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAVlpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KTMInWQAAAVJJREFUOBGV0ksrRGEcx/FjhmJBLGyUCElRyuUNaIp4B1ayUd6AjbLxjixtZBALElGuRQmRSwkpl+/3zDmTOcYY//qcy3P5nfM85wRBEKRgdWEaDd5QcXvu7o9jL/2v+MQeamGVHTLLYCffROdFzlZFJLwpdWih8w6GnCEDl1MJy6CilabVQffYQjtmMI9n9GMZLsXwH2XABzwfw1cfwwjasI8erMMHObagnGiZ7lMeMYhNDKMet2jEDqpQEBIH0J6vNa4yWME4DK3BG05QEJIMiNeaZeAoljCJA3TgHFdwXrgnyQAbbXvHNoawgSmsYgCH8IuFXyYZQHuY7IY9wSf24QiGuKkv8GcL36JYAH3hRrnWa/iHNkVtbmQ1mrGL9G8B9OVDTrn2186iE3N4wAJKzac7Vy7H6oZLcp8ukELZFYc4YQKXcIP/Vd+fWMfMVmd/AZ8ZSPZy3VL5AAAAAElFTkSuQmCC"); } .save-icon { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAUUlEQVQ4T2NkYGD4z0AeWMDAwJDISIEBIGsXIBuAyzCQOAjAXAriJzAwMMwHCZJrANzAoWEAehyhhAm6F0iJUHCgjhow2MKAlCiEq6U0NzIAAGhyJqIFiXmZAAAAAElFTkSuQmCC"); } .cancel-icon { background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAv0lEQVQ4T6WT7RHBQBRFTyqgA3RAB0rQASoQHShBOtAJKpASlKAD5mR2Z3YIJrvvV5K3e+59H6kojAo4AZuEMwV2wBKYh+8tcAEa4J5qCngGyBY4hsu/fHlmHw9EgO8PYBwSKulMZUMnNbBOHC18TgERaiJefHciyFJGoZy6D6Cy5XwLIbeQnPUBzP2DmLecRkBORBdtLkBRp9c1MTeKAC7ZGbjmOogLl9XEjzEO7YH/wiRdpKEAHRyAVekUOuEXS4Mk/lKeo50AAAAASUVORK5CYII="); } .action-btn { background-color: transparent; border: 0; display: inline-block; height: 100%; outline: none; padding-left: 6px; padding-right: 6px; } .action-btn span { display: block; height: 16px; width: 16px; } .gc-action-area { text-align: center; } /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkZlYXR1cmVzL0VkaXRpbmcvQmF0Y2hFZGl0L3B1cmVqcy9zdHlsZXMuc2NzcyIsIkZlYXR1cmVzL0VkaXRpbmcvQmF0Y2hFZGl0L3B1cmVqcy9zdHlsZXMuY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0VBQ0UsYUFBQTtFQUNBLHNCQUFBO0VBQ0EsV0FBQTtFQUNBLFlBQUE7RUFDQSxjQUFBO0FDQ0Y7O0FERUE7RUFDRSxtQkFBQTtFQUNBLHNCQUFBO0VBQ0EsWUFBQTtFQUNBLGNBQUE7RUFDQSxhQUFBO0VBQ0EsWUFBQTtFQUNBLGNBQUE7QUNDRjtBRENFO0VBQ0UsYUFBQTtFQUNBLG1CQUFBO0VBQ0EsdUJBQUE7RUFDQSxZQUFBO0FDQ0o7O0FER0E7RUFDRSx5QkFBQTtFQUNBLGlCQUFBO0VBQ0EsV0FBQTtFQUNBLFlBQUE7RUFDQSxjQUFBO0FDQUY7O0FER0E7RUFDRSx5QkFBQTtFQUNBLGFBQUE7RUFDQSxtQkFBQTtBQ0FGOztBREdBO0VBQ0UsYUFBQTtFQUNBLG1CQUFBO0VBQ0EsdUJBQUE7RUFDQSxrQkFBQTtFQUNBLFdBQUE7QUNBRjs7QURHQTtFQUNFLDYyQkFBQTtFQUNBLDRCQUFBO0VBQ0EsU0FBQTtFQUNBLGtCQUFBO0VBQ0EsZUFBQTtFQUNBLFlBQUE7RUFDQSxpQkFBQTtFQUNBLFVBQUE7RUFDQSxXQUFBO0FDQUY7O0FER0E7RUFDRSxpa0NBQUE7QUNBRjs7QURHQTtFQUNFLGlPQUFBO0FDQUY7O0FER0E7RUFDRSxxWEFBQTtBQ0FGOztBREdBO0VBQ0UsNkJBQUE7RUFDQSxTQUFBO0VBQ0EscUJBQUE7RUFDQSxZQUFBO0VBQ0EsYUFBQTtFQUNBLGlCQUFBO0VBQ0Esa0JBQUE7QUNBRjtBREVFO0VBQ0UsY0FBQTtFQUNBLFlBQUE7RUFDQSxXQUFBO0FDQUo7O0FESUE7RUFDRSxrQkFBQTtBQ0RGIiwiZmlsZSI6IkZlYXR1cmVzL0VkaXRpbmcvQmF0Y2hFZGl0L3B1cmVqcy9zdHlsZXMuY3NzIiwic291cmNlc0NvbnRlbnQiOlsiLm1haW4tY29udGFpbmVyIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcbiAgb3ZlcmZsb3c6IGF1dG87XG59XG5cbi5zYW1wbGUtb3B0aW9ucyB7XG4gIGJhY2tncm91bmQ6ICNmYmZiZmI7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGZsb2F0OiByaWdodDtcbiAgb3ZlcmZsb3c6IGF1dG87XG4gIHBhZGRpbmc6IDEwcHg7XG4gIGZsZXgtZ3JvdzogMDtcbiAgZmxleC1zaHJpbms6IDA7XG5cbiAgLmJ0biB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGhlaWdodDogMzJweDtcbiAgfVxufVxuXG4jZ3JpZCB7XG4gIGhlaWdodDogY2FsYygxMDAlIC0gOTVweCk7XG4gIG1pbi1oZWlnaHQ6IDIwMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgZmxleC1ncm93OiAwO1xuICBmbGV4LXNocmluazogMDtcbn1cblxuLmdjLWhlYWRlci1yb3ctY2VsbCB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlYWVhZWE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG59XG5cbiNidG5BZGROZXcge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYm9yZGVyLXJhZGl1czogNXB4O1xuICBtYXJnaW46IDVweDtcbn1cblxuLmFkZC1pY29uIHtcbiAgYmFja2dyb3VuZDogdXJsKCdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUJRQUFBQVVDQVlBQUFDTmlSME5BQUFBQm1KTFIwUUEvd0QvQVArZ3ZhZVRBQUFBQ1hCSVdYTUFBQTdDQUFBT3dnRVZLRXFBQUFBQUIzUkpUVVVIM1FzSkFURXJBNDlQRHdBQUFnQkpSRUZVT011dDFUMUlWV0VZQi9EZlBmZEtYeFRSa0ZGRDBLVWhEVUlvdEVZSGwwS2tvS2xGK3FCSW9xR0dsb1pvcTZFUHBhQWlDR21JRERWYWE0c2dTWVN5YUlpaUVFa1NLNFJFcjdmbE9YQTYzTnNIOU1DQncvcyt6Ly81L3IrRmpvNE9OV1FyZG1Ndm1sR044d0plNFFFZTRXWGVzSkFEWEltVE9JMDVQTWN6VE1mOUdyUmhCNWJnQWk3aGV3cFF5b0N0UXkvMjRWNG9qNmd0MjhQcE9XeEREeWF6Z0t2Umh6MDRobHVZVjE5R2NBQlBjRGxLY1JBektXQlAxT3N3YnZvN21jZDFMT0FHUm5HK1dDNlhtM0VIOTNFMjA0QlVWbUVYMW1NcUFMSXloczA0aEtFRW5lSHRJaW8xSXRtQ0FkekcyaHIzbGJDZFIyZUNManlOa091bFZveDYvNmlqTXhvWVhRbWFZalN5cWE3QUpqUkdxZ1VrMklnTjhUVms5S3VCMFZRS3hTODVqKzNSbkc5WUhnNldSZXBWZkVJMzNtWnNwcEVrb1ZEeG42UVVnSTI1ODhmWWlkbllpcnVSeFg1TWhNN25uTTBhTEpZd2p0YW9VMXJIV2J5TC80azRYOFNIR2tEcGpyZGhQTUZnekZsTG5Td2FvaVFMV0ZwSHB5VXdCaE1NaDlHcEdJKzh2STc5N3E0VFhURnNHekJjTEpmTFU5SHBFL2lJRnptRE9ieVB1NFVhZ0Vkd0pvaGlJTjNsM2dpN0x4cjFKM0pJUzNFMHlHRUFWMFZrTUlQamVJaHI2QStLOGh2NjZzZVY0SUFlZk0zejRXVFVhU3k0cmoxSHNKWFk1ZFlZcFdLUXlTOEVXL2lISjZBYUdhVlB3QkRlNUExL0Fnb2pnd3VSWEM2QkFBQUFBRWxGVGtTdVFtQ0MnKTtcbiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgYm9yZGVyOiAwO1xuICBjb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgaGVpZ2h0OiAyMHB4O1xuICBtYXJnaW4tcmlnaHQ6IDVweDtcbiAgcGFkZGluZzogMDtcbiAgd2lkdGg6IDIwcHg7XG59XG5cbi5lZGl0LWljb24ge1xuICBiYWNrZ3JvdW5kOiB1cmwoJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUFBWE5TUjBJQXJzNGM2UUFBQUFsd1NGbHpBQUFMRXdBQUN4TUJBSnFjR0FBQUFWbHBWRmgwV0UxTU9tTnZiUzVoWkc5aVpTNTRiWEFBQUFBQUFEeDRPbmh0Y0cxbGRHRWdlRzFzYm5NNmVEMGlZV1J2WW1VNmJuTTZiV1YwWVM4aUlIZzZlRzF3ZEdzOUlsaE5VQ0JEYjNKbElEVXVOQzR3SWo0S0lDQWdQSEprWmpwU1JFWWdlRzFzYm5NNmNtUm1QU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUx6QXlMekl5TFhKa1ppMXplVzUwWVhndGJuTWpJajRLSUNBZ0lDQWdQSEprWmpwRVpYTmpjbWx3ZEdsdmJpQnlaR1k2WVdKdmRYUTlJaUlLSUNBZ0lDQWdJQ0FnSUNBZ2VHMXNibk02ZEdsbVpqMGlhSFIwY0RvdkwyNXpMbUZrYjJKbExtTnZiUzkwYVdabUx6RXVNQzhpUGdvZ0lDQWdJQ0FnSUNBOGRHbG1aanBQY21sbGJuUmhkR2x2Ymo0eFBDOTBhV1ptT2s5eWFXVnVkR0YwYVc5dVBnb2dJQ0FnSUNBOEwzSmtaanBFWlhOamNtbHdkR2x2Ymo0S0lDQWdQQzl5WkdZNlVrUkdQZ284TDNnNmVHMXdiV1YwWVQ0S1RNSW5XUUFBQVZKSlJFRlVPQkdWMGtzclJHRWN4L0ZqaG1KQkxHeVVDRWxSeXVVTmFJcDRCMWF5VWQ2QWpiTHhqaXh0WkJBTEVsR3VSUW1SU3drcGwrLzN6RG1UT2NZWS8vcWN5M1A1bmZNODV3UkJFS1JnZFdFYURkNVFjWHZ1N285akwvMnYrTVFlYW1HVkhUTExZQ2ZmUk9kRnpsWkZKTHdwZFdpaDh3NkduQ0VEbDFNSnk2Q2lsYWJWUWZmWVFqdG1NSTluOUdNWkxzWHdIMlhBQnp3ZncxY2Z3d2phc0k4ZXJNTUhPYmFnbkdpWjdsTWVNWWhOREtNZXQyakVEcXBRRUJJSDBKNnZOYTR5V01FNERLM0JHMDVRRUpJTWlOZWFaZUFvbGpDSkEzVGdIRmR3WHJnbnlRQWJiWHZITm9hd2dTbXNZZ0NIOEl1Rlh5WVpRSHVZN0lZOXdTZjI0UWlHdUtrdjhHY0wzNkpZQUgzaFJybldhL2lITmtWdGJtUTFtckdMOUc4QjlPVkRUcm4yMTg2aUUzTjR3QUpLemFjN1Z5N0g2b1pMY3A4dWtFTFpGWWM0WVFLWGNJUC9WZCtmV01mTVZtZC9BWjhaU1BaeTNWTDVBQUFBQUVsRlRrU3VRbUNDJyk7XG59XG5cbi5zYXZlLWljb24ge1xuICBiYWNrZ3JvdW5kOiB1cmwoJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUFVVWxFUVZRNFQyTmtZR0Q0ejBBZVdNREF3SkRJU0lFQklHc1hJQnVBeXpDUU9BakFYQXJpSnpBd01Nd0hDWkpyQU56QW9XRUFlaHloaEFtNkYwaUpVSENnamhvdzJNS0FsQ2lFcTZVME56SUFBR2h5SnFJRmlYbVpBQUFBQUVsRlRrU3VRbUNDJyk7XG59XG5cbi5jYW5jZWwtaWNvbiB7XG4gIGJhY2tncm91bmQ6IHVybCgnZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCQUFBQUFRQ0FZQUFBQWY4LzloQUFBQXYwbEVRVlE0VDZXVDdSSEJRQlJGVHlxZ0EzUkFCMHJRQVNvUUhTaEJPdEFKS3BBU2xLQUQ1bVIyWjNZSUpydnZWNUszZSs1OUg2a29qQW80QVp1RU13VjJ3QktZaCs4dGNBRWE0SjVxQ25nR3lCWTRoc3UvZkhsbUh3OUVnTzhQWUJ3U0t1bE1aVU1uTmJCT0hDMThUZ0VSYWlKZWZIY2l5RkpHb1p5NkQ2Q3k1WHdMSWJlUW5QVUJ6UDJEbUxlY1JrQk9SQmR0TGtCUnA5YzFNVGVLQUM3Wkdiam1Pb2dMbDlYRWp6RU83WUgvd2lSZHBLRUFIUnlBVmVrVU91RVhTNE1rL2xLZW81MEFBQUFBU1VWT1JLNUNZSUk9Jyk7XG59XG5cbi5hY3Rpb24tYnRuIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGJvcmRlcjogMDtcbiAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xuICBoZWlnaHQ6IDEwMCU7XG4gIG91dGxpbmU6IG5vbmU7XG4gIHBhZGRpbmctbGVmdDogNnB4O1xuICBwYWRkaW5nLXJpZ2h0OiA2cHg7XG5cbiAgc3BhbiB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgaGVpZ2h0OiAxNnB4O1xuICAgIHdpZHRoOiAxNnB4O1xuICB9XG59XG5cbi5nYy1hY3Rpb24tYXJlYSB7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbn1cbiIsIi5tYWluLWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIHdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IDEwMCU7XG4gIG92ZXJmbG93OiBhdXRvO1xufVxuXG4uc2FtcGxlLW9wdGlvbnMge1xuICBiYWNrZ3JvdW5kOiAjZmJmYmZiO1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBmbG9hdDogcmlnaHQ7XG4gIG92ZXJmbG93OiBhdXRvO1xuICBwYWRkaW5nOiAxMHB4O1xuICBmbGV4LWdyb3c6IDA7XG4gIGZsZXgtc2hyaW5rOiAwO1xufVxuLnNhbXBsZS1vcHRpb25zIC5idG4ge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgaGVpZ2h0OiAzMnB4O1xufVxuXG4jZ3JpZCB7XG4gIGhlaWdodDogY2FsYygxMDAlIC0gOTVweCk7XG4gIG1pbi1oZWlnaHQ6IDIwMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgZmxleC1ncm93OiAwO1xuICBmbGV4LXNocmluazogMDtcbn1cblxuLmdjLWhlYWRlci1yb3ctY2VsbCB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlYWVhZWE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG59XG5cbiNidG5BZGROZXcge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYm9yZGVyLXJhZGl1czogNXB4O1xuICBtYXJnaW46IDVweDtcbn1cblxuLmFkZC1pY29uIHtcbiAgYmFja2dyb3VuZDogdXJsKFwiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCUUFBQUFVQ0FZQUFBQ05pUjBOQUFBQUJtSkxSMFFBL3dEL0FQK2d2YWVUQUFBQUNYQklXWE1BQUE3Q0FBQU93Z0VWS0VxQUFBQUFCM1JKVFVVSDNRc0pBVEVyQTQ5UER3QUFBZ0JKUkVGVU9NdXQxVDFJVldFWUIvRGZQZmRLWHhUUmtGRkQwS1VoRFVJb3RFWUhsMEtrb0tsRitxQklvcUdHbG9ab3E2RVBwYUFpQ0dtSUREVmFhNHNnU1lTeWFJaWlFRWtTSzRSRXI3ZmxPWEE2M05zSDlNQ0J3L3Mrei8vNS9yK0ZqbzRPTldRcmRtTXZtbEdOOHdKZTRRRWU0V1hlc0pBRFhJbVRPSTA1UE1jelRNZjlHclJoQjViZ0FpN2hld3BReW9DdFF5LzI0VjRvajZndDI4UHBPV3hERHlhemdLdlJoejA0aGx1WVYxOUdjQUJQY0RsS2NSQXpLV0JQMU9zd2J2bzdtY2QxTE9BR1JuRytXQzZYbTNFSDkzRTIwNEJVVm1FWDFtTXFBTEl5aHMwNGhLRUVuZUh0SWlvMUl0bUNBZHpHMmhyM2xiQ2RSMmVDTGp5TmtPdWxWb3g2LzZpak14b1lYUW1hWWpTeXFhN0FKalJHcWdVazJJZ044VFZrOUt1QjBWUUt4Uzg1aiszUm5HOVlIZzZXUmVwVmZFSTMzbVpzcHBFa29WRHhuNlFVZ0kyNTg4ZllpZG5ZaXJ1UnhYNU1oTTdubk0wYUxKWXdqdGFvVTFySFdieUwvNGs0WDhTSEdrRHBqcmRoUE1GZ3pGbExuU3dhb2lRTFdGcEhweVV3QmhNTWg5R3BHSSs4dkk3OTdxNFRYVEZzR3pCY0xKZkxVOUhwRS9pSUZ6bURPYnlQdTRVYWdFZHdKb2hpSU4zbDNnaTdMeHIxSjNKSVMzRTB5R0VBVjBWa01JUGplSWhyNkErSzhodjY2c2VWNElBZWZNM3o0V1RVYVN5NHJqMUhzSlhZNWRZWXBXS1F5UzhFVy9pSEo2QWFHYVZQd0JEZTVBMS9BZ29qZ3d1UlhDNkJBQUFBQUVsRlRrU3VRbUNDXCIpO1xuICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0O1xuICBib3JkZXI6IDA7XG4gIGNvbG9yOiB0cmFuc3BhcmVudDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBoZWlnaHQ6IDIwcHg7XG4gIG1hcmdpbi1yaWdodDogNXB4O1xuICBwYWRkaW5nOiAwO1xuICB3aWR0aDogMjBweDtcbn1cblxuLmVkaXQtaWNvbiB7XG4gIGJhY2tncm91bmQ6IHVybChcImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUFBWE5TUjBJQXJzNGM2UUFBQUFsd1NGbHpBQUFMRXdBQUN4TUJBSnFjR0FBQUFWbHBWRmgwV0UxTU9tTnZiUzVoWkc5aVpTNTRiWEFBQUFBQUFEeDRPbmh0Y0cxbGRHRWdlRzFzYm5NNmVEMGlZV1J2WW1VNmJuTTZiV1YwWVM4aUlIZzZlRzF3ZEdzOUlsaE5VQ0JEYjNKbElEVXVOQzR3SWo0S0lDQWdQSEprWmpwU1JFWWdlRzFzYm5NNmNtUm1QU0pvZEhSd09pOHZkM2QzTG5jekxtOXlaeTh4T1RrNUx6QXlMekl5TFhKa1ppMXplVzUwWVhndGJuTWpJajRLSUNBZ0lDQWdQSEprWmpwRVpYTmpjbWx3ZEdsdmJpQnlaR1k2WVdKdmRYUTlJaUlLSUNBZ0lDQWdJQ0FnSUNBZ2VHMXNibk02ZEdsbVpqMGlhSFIwY0RvdkwyNXpMbUZrYjJKbExtTnZiUzkwYVdabUx6RXVNQzhpUGdvZ0lDQWdJQ0FnSUNBOGRHbG1aanBQY21sbGJuUmhkR2x2Ymo0eFBDOTBhV1ptT2s5eWFXVnVkR0YwYVc5dVBnb2dJQ0FnSUNBOEwzSmtaanBFWlhOamNtbHdkR2x2Ymo0S0lDQWdQQzl5WkdZNlVrUkdQZ284TDNnNmVHMXdiV1YwWVQ0S1RNSW5XUUFBQVZKSlJFRlVPQkdWMGtzclJHRWN4L0ZqaG1KQkxHeVVDRWxSeXVVTmFJcDRCMWF5VWQ2QWpiTHhqaXh0WkJBTEVsR3VSUW1SU3drcGwrLzN6RG1UT2NZWS8vcWN5M1A1bmZNODV3UkJFS1JnZFdFYURkNVFjWHZ1N285akwvMnYrTVFlYW1HVkhUTExZQ2ZmUk9kRnpsWkZKTHdwZFdpaDh3NkduQ0VEbDFNSnk2Q2lsYWJWUWZmWVFqdG1NSTluOUdNWkxzWHdIMlhBQnp3ZncxY2Z3d2phc0k4ZXJNTUhPYmFnbkdpWjdsTWVNWWhOREtNZXQyakVEcXBRRUJJSDBKNnZOYTR5V01FNERLM0JHMDVRRUpJTWlOZWFaZUFvbGpDSkEzVGdIRmR3WHJnbnlRQWJiWHZITm9hd2dTbXNZZ0NIOEl1Rlh5WVpRSHVZN0lZOXdTZjI0UWlHdUtrdjhHY0wzNkpZQUgzaFJybldhL2lITmtWdGJtUTFtckdMOUc4QjlPVkRUcm4yMTg2aUUzTjR3QUpLemFjN1Z5N0g2b1pMY3A4dWtFTFpGWWM0WVFLWGNJUC9WZCtmV01mTVZtZC9BWjhaU1BaeTNWTDVBQUFBQUVsRlRrU3VRbUNDXCIpO1xufVxuXG4uc2F2ZS1pY29uIHtcbiAgYmFja2dyb3VuZDogdXJsKFwiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCQUFBQUFRQ0FZQUFBQWY4LzloQUFBQVVVbEVRVlE0VDJOa1lHRDR6MEFlV01EQXdKRElTSUVCSUdzWElCdUF5ekNRT0FqQVhBcmlKekF3TU13SENaSnJBTnpBb1dFQWVoeWhoQW02RjBpSlVIQ2dqaG93Mk1LQWxDaUVxNlUwTnpJQUFHaHlKcUlGaVhtWkFBQUFBRWxGVGtTdVFtQ0NcIik7XG59XG5cbi5jYW5jZWwtaWNvbiB7XG4gIGJhY2tncm91bmQ6IHVybChcImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBQkFBQUFBUUNBWUFBQUFmOC85aEFBQUF2MGxFUVZRNFQ2V1Q3UkhCUUJSRlR5cWdBM1JBQjByUUFTb1FIU2hCT3RBSktwQVNsS0FENW1SMlozWUlKcnZ2VjVLM2UrNTlINmtvakFvNEFadUVNd1Yyd0JLWWgrOHRjQUVhNEo1cUNuZ0d5Qlk0aHN1L2ZIbG1IdzlFZ084UFlCd1NLdWxNWlVNbk5iQk9IQzE4VGdFUmFpSmVmSGNpeUZKR29aeTZENkN5NVh3TEliZVFuUFVCelAyRG1MZWNSa0JPUkJkdExrQlJwOWMxTVRlS0FDN1pHYmptT29nTGw5WEVqekVPN1lIL3dpUmRwS0VBSFJ5QVZla1VPdUVYUzRNay9sS2VvNTBBQUFBQVNVVk9SSzVDWUlJPVwiKTtcbn1cblxuLmFjdGlvbi1idG4ge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDtcbiAgYm9yZGVyOiAwO1xuICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gIGhlaWdodDogMTAwJTtcbiAgb3V0bGluZTogbm9uZTtcbiAgcGFkZGluZy1sZWZ0OiA2cHg7XG4gIHBhZGRpbmctcmlnaHQ6IDZweDtcbn1cbi5hY3Rpb24tYnRuIHNwYW4ge1xuICBkaXNwbGF5OiBibG9jaztcbiAgaGVpZ2h0OiAxNnB4O1xuICB3aWR0aDogMTZweDtcbn1cblxuLmdjLWFjdGlvbi1hcmVhIHtcbiAgdGV4dC1hbGlnbjogY2VudGVyO1xufSJdfQ== */