diff --git a/docs/README.md b/docs/README.md index 4f46655..61a04aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -8,9 +8,11 @@ Additional features: Export documents to JSON. Import documents from JSON. ISODa Screenshots ----------- -![MongoDB PHP GUI](https://raw.githubusercontent.com/SamuelTS/MongoDB-PHP-GUI/master/docs/screenshots/new-mpg-database-query.png) +![MongoDB PHP GUI - Visualize Database](https://raw.githubusercontent.com/SamuelTS/MongoDB-PHP-GUI/master/docs/screenshots/newest-mpg-database-visualize.png) -![MongoDB PHP GUI](https://raw.githubusercontent.com/SamuelTS/MongoDB-PHP-GUI/master/docs/screenshots/new-mpg-collection-indexes.png) +![MongoDB PHP GUI - Query Database](https://raw.githubusercontent.com/SamuelTS/MongoDB-PHP-GUI/master/docs/screenshots/newest-mpg-database-query.png) + +![MongoDB PHP GUI - Manage Indexes](https://raw.githubusercontent.com/SamuelTS/MongoDB-PHP-GUI/master/docs/screenshots/newest-mpg-collection-indexes.png) Installation ------------ @@ -24,7 +26,7 @@ Thanks ------ ❤️ Thanks to [Limber](https://github.com/nimbly/Limber), [Capsule](https://github.com/nimbly/Capsule), [Font Awesome](https://fontawesome.com/), [Bootstrap](https://getbootstrap.com/), [CodeMirror](https://github.com/codemirror/codemirror) and [JsonView](https://github.com/pgrabovets/json-view).
-Special thanks to [MongoDB PHP library](https://github.com/mongodb/mongo-php-library) and [SQL to MongoDB Query Converter](https://github.com/vincentrussell/sql-to-mongo-db-query-converter). ❤️ +Thanks also to [MongoDB PHP lib](https://github.com/mongodb/mongo-php-library), [vis.js](https://github.com/visjs) and [SQL to MongoDB Query Converter](https://github.com/vincentrussell/sql-to-mongo-db-query-converter). ❤️ Copyright --------- diff --git a/docs/screenshots/new-mpg-collection-indexes.png b/docs/screenshots/new-mpg-collection-indexes.png deleted file mode 100644 index d141ed4..0000000 Binary files a/docs/screenshots/new-mpg-collection-indexes.png and /dev/null differ diff --git a/docs/screenshots/new-mpg-database-query.png b/docs/screenshots/new-mpg-database-query.png deleted file mode 100644 index 8c7eb81..0000000 Binary files a/docs/screenshots/new-mpg-database-query.png and /dev/null differ diff --git a/docs/screenshots/newest-mpg-collection-indexes.png b/docs/screenshots/newest-mpg-collection-indexes.png new file mode 100644 index 0000000..0794ed8 Binary files /dev/null and b/docs/screenshots/newest-mpg-collection-indexes.png differ diff --git a/docs/screenshots/newest-mpg-database-query.png b/docs/screenshots/newest-mpg-database-query.png new file mode 100644 index 0000000..489760e Binary files /dev/null and b/docs/screenshots/newest-mpg-database-query.png differ diff --git a/docs/screenshots/newest-mpg-database-visualize.png b/docs/screenshots/newest-mpg-database-visualize.png new file mode 100644 index 0000000..b794b7b Binary files /dev/null and b/docs/screenshots/newest-mpg-database-visualize.png differ diff --git a/index.php b/index.php index 9b8a025..76e6ed6 100644 --- a/index.php +++ b/index.php @@ -18,7 +18,7 @@ * * @var string */ -define('MPG_APP_VERSION', '1.0.5'); +define('MPG_APP_VERSION', '1.0.6'); /** * Development mode? diff --git a/routes.php b/routes.php index 7d487e3..55dacd9 100644 --- a/routes.php +++ b/routes.php @@ -66,6 +66,16 @@ CollectionController::class . '@renderImportViewAction' ); +$router->get( + MPG_SERVER_PATH . '/visualizeDatabase', + DatabaseController::class . '@renderVisualizeViewAction' +); + +$router->get( + MPG_SERVER_PATH . '/ajaxDatabaseGetNetworkGraph', + DatabaseController::class . '@getNetworkGraphAction' +); + $router->get( MPG_SERVER_PATH . '/queryDatabase', DatabaseController::class . '@renderQueryViewAction' diff --git a/src/Controllers/DatabaseController.php b/src/Controllers/DatabaseController.php index 2bd582e..c68acdc 100644 --- a/src/Controllers/DatabaseController.php +++ b/src/Controllers/DatabaseController.php @@ -31,6 +31,107 @@ public static function getDatabaseNames() : array { } + public function renderVisualizeViewAction() : Response { + + LoginController::ensureUserIsLogged(); + + return new Response(200, $this->renderView('database.visualize')); + + } + + public function getNetworkGraphAction() : Response { + + $networkGraph = [ + 'visData' => [ + 'nodes' => [ + [ + 'id' => 1, + 'label' => 'MongoDB server', + 'shape' => 'image', + 'image' => MPG_BASE_URL . '/static/images/leaf-icon.svg', + 'size' => 32 + ] + ], + 'edges' => [] + ], + 'mapping' => [ + + 1 => [ + 'databaseName' => null, + 'collectionName' => null + ] + + ] + ]; + + $nodeCounter = 1; + + try { + + foreach (MongoDBHelper::getClient()->listDatabases() as $databaseInfo) { + + $nodeCounter++; + + $databaseNode = [ + 'id' => $nodeCounter, + 'label' => 'DB: ' . $databaseInfo['name'], + 'shape' => 'image', + 'image' => MPG_BASE_URL . '/static/images/database-icon.svg', + 'size' => 24 + ]; + + $database = MongoDBHelper::getClient()->selectDatabase( + $databaseInfo['name'] + ); + + foreach ($database->listCollections() as $collectionInfo) { + + $nodeCounter++; + + $collectionNode = [ + 'id' => $nodeCounter, + 'label' => 'Coll: ' . $collectionInfo['name'], + 'shape' => 'image', + 'image' => MPG_BASE_URL . '/static/images/document-icon.svg', + 'size' => 24 + ]; + + array_push($networkGraph['visData']['nodes'], $collectionNode); + + array_push($networkGraph['visData']['edges'], [ + 'from' => $databaseNode['id'], + 'to' => $collectionNode['id'] + ]); + + $networkGraph['mapping'][ $collectionNode['id'] ] = [ + 'databaseName' => $databaseInfo['name'], + 'collectionName' => $collectionInfo['name'] + ]; + + } + + array_push($networkGraph['visData']['nodes'], $databaseNode); + + array_push($networkGraph['visData']['edges'], [ + 'from' => 1, // MongoDB server + 'to' => $databaseNode['id'] + ]); + + $networkGraph['mapping'][ $databaseNode['id'] ] = [ + 'databaseName' => $databaseInfo['name'], + 'collectionName' => null + ]; + + } + + } catch (\Throwable $th) { + return new JsonResponse(500, ErrorNormalizer::normalize($th, __METHOD__)); + } + + return new JsonResponse(200, $networkGraph); + + } + public function renderQueryViewAction() : Response { LoginController::ensureUserIsLogged(); diff --git a/static/css/mpg.css b/static/css/mpg.css index c6bae6b..20f3771 100644 --- a/static/css/mpg.css +++ b/static/css/mpg.css @@ -145,6 +145,12 @@ } +.vis-network:focus { + + outline: none; + +} + code { font-size: 100%; diff --git a/static/images/database-icon.svg b/static/images/database-icon.svg new file mode 100644 index 0000000..969d273 --- /dev/null +++ b/static/images/database-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/images/document-icon.svg b/static/images/document-icon.svg new file mode 100644 index 0000000..dfc34d3 --- /dev/null +++ b/static/images/document-icon.svg @@ -0,0 +1,20 @@ + + + + background + + + + Layer 1 + + + + + + + + + + + + \ No newline at end of file diff --git a/static/images/leaf-icon.svg b/static/images/leaf-icon.svg new file mode 100644 index 0000000..db43e67 --- /dev/null +++ b/static/images/leaf-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/js/mpg.database.query.js b/static/js/mpg.database.query.js index 1704c1a..6446eca 100644 --- a/static/js/mpg.database.query.js +++ b/static/js/mpg.database.query.js @@ -489,6 +489,8 @@ MPG.eventListeners.addCollections = function() { document.querySelector('#mpg-output-code').innerHTML = ''; + document.querySelector('#mpg-find-button').click(); + }, JSON.stringify(requestBody) ); diff --git a/static/js/mpg.database.visualize.js b/static/js/mpg.database.visualize.js new file mode 100644 index 0000000..84c9fa3 --- /dev/null +++ b/static/js/mpg.database.visualize.js @@ -0,0 +1,146 @@ + +/** + * MongoDB PHP GUI namespace. + * + * @type {object} + */ +var MPG = {}; + +/** + * vis.Network options. + * + * @type {object} + */ +MPG.visNetworkOptions = { + + width: '100%', + height: '400px', + nodes: { + color: { + background: "transparent", + border: "transparent" + } + }, + edges: { + width: 1, + color: { + color: '#ddd', + highlight: '#0062cc' + }, + } + +}; + +/** + * Helpers sub-namespace. + * + * @type {object} + */ +MPG.helpers = {}; + +/** + * Does an ajax request. + * + * @param {string} method + * @param {string} url + * @param {function} successCallback + * @param {?string} body + * + * @returns {void} + */ +MPG.helpers.doAjaxRequest = function(method, url, successCallback, body) { + + var xhr = new XMLHttpRequest(); + + xhr.addEventListener('readystatechange', function() { + + if ( this.readyState === 4 ) { + if ( this.status === 200 ) { + successCallback(this.responseText); + } else { + window.alert('Error: ' + JSON.parse(this.responseText).error.message); + } + } + + }); + + xhr.open(method, url); + xhr.send(body); + +}; + +/** + * Event listeners sub-namespace. + * + * @type {object} + */ +MPG.eventListeners = {}; + +/** + * Adds an event listener on "Menu toggle" button. + * + * @returns {void} + */ +MPG.eventListeners.addMenuToggle = function() { + + document.querySelector('#menu-toggle-button').addEventListener('click', function(_event) { + document.querySelector('.navbar').classList.toggle('menu-expanded'); + }); + +}; + +/** + * Draws vis.Network. + */ +MPG.drawVisNetwork = function() { + + MPG.helpers.doAjaxRequest( + 'GET', + MPG_BASE_URL + '/ajaxDatabaseGetNetworkGraph', + function(response) { + + var visNetworkContainer = document.querySelector('#vis-network-container'); + var networkGraph = JSON.parse(response); + + var visNetwork = new vis.Network( + visNetworkContainer, networkGraph.visData, MPG.visNetworkOptions + ); + + visNetwork.on('select', function(nodeProperties) { + + if ( nodeProperties.nodes.length === 0 ) { + return; + } + + var selectedNodeId = nodeProperties.nodes[0]; + var selectedNodeMapping = networkGraph.mapping[selectedNodeId]; + var targetUrl = MPG_BASE_URL + '/queryDatabase#'; + + if ( selectedNodeMapping.databaseName !== null ) { + + targetUrl += selectedNodeMapping.databaseName; + + if ( selectedNodeMapping.collectionName !== null ) { + targetUrl += '/' + selectedNodeMapping.collectionName; + } + + window.location.href = targetUrl; + + } + + + }); + + }, + null + ); + +}; + +// When document is ready: +window.addEventListener('DOMContentLoaded', function(_event) { + + MPG.eventListeners.addMenuToggle(); + MPG.drawVisNetwork(); + +}); diff --git a/static/js/vis-network.min.js b/static/js/vis-network.min.js new file mode 100644 index 0000000..8f2b946 --- /dev/null +++ b/static/js/vis-network.min.js @@ -0,0 +1,51 @@ +/** + * vis-network + * https://visjs.github.io/vis-network/ + * + * A dynamic, browser-based visualization library. + * + * @version 8.2.0 + * @date 2020-08-13T21:45:20.240Z + * + * @copyright (c) 2011-2017 Almende B.V, http://almende.com + * @copyright (c) 2017-2019 visjs contributors, https://github.com/visjs + * + * @license + * vis.js is dual licensed under both + * + * 1. The Apache 2.0 License + * http://www.apache.org/licenses/LICENSE-2.0 + * + * and + * + * 2. The MIT License + * http://opensource.org/licenses/MIT + * + * vis.js may be distributed under either license. + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).vis=t.vis||{})}(this,(function(t){"use strict";var e="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function i(t,e){return t(e={exports:{}},e.exports),e.exports}var o=function(t){return t&&t.Math==Math&&t},n=o("object"==typeof globalThis&&globalThis)||o("object"==typeof window&&window)||o("object"==typeof self&&self)||o("object"==typeof e&&e)||Function("return this")(),r=function(t){try{return!!t()}catch(t){return!0}},s=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]})),a={}.propertyIsEnumerable,h=Object.getOwnPropertyDescriptor,l={f:h&&!a.call({1:2},1)?function(t){var e=h(this,t);return!!e&&e.enumerable}:a},d=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},c={}.toString,u=function(t){return c.call(t).slice(8,-1)},f="".split,p=r((function(){return!Object("z").propertyIsEnumerable(0)}))?function(t){return"String"==u(t)?f.call(t,""):Object(t)}:Object,v=function(t){if(null==t)throw TypeError("Can't call method on "+t);return t},g=function(t){return p(v(t))},y=function(t){return"object"==typeof t?null!==t:"function"==typeof t},m=function(t,e){if(!y(t))return t;var i,o;if(e&&"function"==typeof(i=t.toString)&&!y(o=i.call(t)))return o;if("function"==typeof(i=t.valueOf)&&!y(o=i.call(t)))return o;if(!e&&"function"==typeof(i=t.toString)&&!y(o=i.call(t)))return o;throw TypeError("Can't convert object to primitive value")},b={}.hasOwnProperty,w=function(t,e){return b.call(t,e)},k=n.document,_=y(k)&&y(k.createElement),x=function(t){return _?k.createElement(t):{}},O=!s&&!r((function(){return 7!=Object.defineProperty(x("div"),"a",{get:function(){return 7}}).a})),E=Object.getOwnPropertyDescriptor,C={f:s?E:function(t,e){if(t=g(t),e=m(e,!0),O)try{return E(t,e)}catch(t){}if(w(t,e))return d(!l.f.call(t,e),t[e])}},S=/#|\.prototype\./,T=function(t,e){var i=M[D(t)];return i==I||i!=P&&("function"==typeof e?r(e):!!e)},D=T.normalize=function(t){return String(t).replace(S,".").toLowerCase()},M=T.data={},P=T.NATIVE="N",I=T.POLYFILL="P",B=T,z={},F=function(t){if("function"!=typeof t)throw TypeError(String(t)+" is not a function");return t},N=function(t,e,i){if(F(t),void 0===e)return t;switch(i){case 0:return function(){return t.call(e)};case 1:return function(i){return t.call(e,i)};case 2:return function(i,o){return t.call(e,i,o)};case 3:return function(i,o,n){return t.call(e,i,o,n)}}return function(){return t.apply(e,arguments)}},A=function(t){if(!y(t))throw TypeError(String(t)+" is not an object");return t},j=Object.defineProperty,R={f:s?j:function(t,e,i){if(A(t),e=m(e,!0),A(i),O)try{return j(t,e,i)}catch(t){}if("get"in i||"set"in i)throw TypeError("Accessors not supported");return"value"in i&&(t[e]=i.value),t}},L=s?function(t,e,i){return R.f(t,e,d(1,i))}:function(t,e,i){return t[e]=i,t},H=C.f,W=function(t){var e=function(e,i,o){if(this instanceof t){switch(arguments.length){case 0:return new t;case 1:return new t(e);case 2:return new t(e,i)}return new t(e,i,o)}return t.apply(this,arguments)};return e.prototype=t.prototype,e},q=function(t,e){var i,o,r,s,a,h,l,d,c=t.target,u=t.global,f=t.stat,p=t.proto,v=u?n:f?n[c]:(n[c]||{}).prototype,g=u?z:z[c]||(z[c]={}),y=g.prototype;for(r in e)i=!B(u?r:c+(f?".":"#")+r,t.forced)&&v&&w(v,r),a=g[r],i&&(h=t.noTargetGet?(d=H(v,r))&&d.value:v[r]),s=i&&h?h:e[r],i&&typeof a==typeof s||(l=t.bind&&i?N(s,n):t.wrap&&i?W(s):p&&"function"==typeof s?N(Function.call,s):s,(t.sham||s&&s.sham||a&&a.sham)&&L(l,"sham",!0),g[r]=l,p&&(w(z,o=c+"Prototype")||L(z,o,{}),z[o][r]=s,t.real&&y&&!y[r]&&L(y,r,s)))},V=[].slice,U={},Y=function(t,e,i){if(!(e in U)){for(var o=[],n=0;n0?J:Z)(t)},et=Math.min,it=function(t){return t>0?et(tt(t),9007199254740991):0},ot=Math.max,nt=Math.min,rt=function(t,e){var i=tt(t);return i<0?ot(i+e,0):nt(i,e)},st=function(t){return function(e,i,o){var n,r=g(e),s=it(r.length),a=rt(o,s);if(t&&i!=i){for(;s>a;)if((n=r[a++])!=n)return!0}else for(;s>a;a++)if((t||a in r)&&r[a]===i)return t||a||0;return!t&&-1}},at={includes:st(!0),indexOf:st(!1)},ht={},lt=at.indexOf,dt=function(t,e){var i,o=g(t),n=0,r=[];for(i in o)!w(ht,i)&&w(o,i)&&r.push(i);for(;e.length>n;)w(o,i=e[n++])&&(~lt(r,i)||r.push(i));return r},ct=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],ut=Object.keys||function(t){return dt(t,ct)},ft={f:Object.getOwnPropertySymbols},pt=function(t){return Object(v(t))},vt=Object.assign,gt=Object.defineProperty,yt=!vt||r((function(){if(s&&1!==vt({b:1},vt(gt({},"a",{enumerable:!0,get:function(){gt(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var t={},e={},i=Symbol();return t[i]=7,"abcdefghijklmnopqrst".split("").forEach((function(t){e[t]=t})),7!=vt({},t)[i]||"abcdefghijklmnopqrst"!=ut(vt({},e)).join("")}))?function(t,e){for(var i=pt(t),o=arguments.length,n=1,r=ft.f,a=l.f;o>n;)for(var h,d=p(arguments[n++]),c=r?ut(d).concat(r(d)):ut(d),u=c.length,f=0;u>f;)h=c[f++],s&&!a.call(d,h)||(i[h]=d[h]);return i}:vt;q({target:"Object",stat:!0,forced:Object.assign!==yt},{assign:yt});var mt=z.Object.assign;function bt(t,e,i,o){t.beginPath(),t.arc(e,i,o,0,2*Math.PI,!1),t.closePath()}function wt(t,e,i,o,n,r){var s=Math.PI/180;o-2*r<0&&(r=o/2),n-2*r<0&&(r=n/2),t.beginPath(),t.moveTo(e+r,i),t.lineTo(e+o-r,i),t.arc(e+o-r,i+r,r,270*s,360*s,!1),t.lineTo(e+o,i+n-r),t.arc(e+o-r,i+n-r,r,0,90*s,!1),t.lineTo(e+r,i+n),t.arc(e+r,i+n-r,r,90*s,180*s,!1),t.lineTo(e,i+r),t.arc(e+r,i+r,r,180*s,270*s,!1),t.closePath()}function kt(t,e,i,o,n){var r=o/2*.5522848,s=n/2*.5522848,a=e+o,h=i+n,l=e+o/2,d=i+n/2;t.beginPath(),t.moveTo(e,d),t.bezierCurveTo(e,d-s,l-r,i,l,i),t.bezierCurveTo(l+r,i,a,d-s,a,d),t.bezierCurveTo(a,d+s,l+r,h,l,h),t.bezierCurveTo(l-r,h,e,d+s,e,d),t.closePath()}function _t(t,e,i,o,n){var r=n*(1/3),s=o/2*.5522848,a=r/2*.5522848,h=e+o,l=i+r,d=e+o/2,c=i+r/2,u=i+(n-r/2),f=i+n;t.beginPath(),t.moveTo(h,c),t.bezierCurveTo(h,c+a,d+s,l,d,l),t.bezierCurveTo(d-s,l,e,c+a,e,c),t.bezierCurveTo(e,c-a,d-s,i,d,i),t.bezierCurveTo(d+s,i,h,c-a,h,c),t.lineTo(h,u),t.bezierCurveTo(h,u+a,d+s,f,d,f),t.bezierCurveTo(d-s,f,e,u+a,e,u),t.lineTo(e,c)}function xt(t,e,i,o,n,r){t.beginPath(),t.moveTo(e,i);for(var s=r.length,a=o-e,h=n-i,l=h/a,d=Math.sqrt(a*a+h*h),c=0,u=!0,f=0,p=+r[0];d>=.1;)(p=+r[c++%s])>d&&(p=d),f=Math.sqrt(p*p/(1+l*l)),e+=f=a<0?-f:f,i+=l*f,!0===u?t.lineTo(e,i):t.moveTo(e,i),d-=p,u=!u}var Ot={circle:bt,dashedLine:xt,database:_t,diamond:function(t,e,i,o){t.beginPath(),t.lineTo(e,i+o),t.lineTo(e+o,i),t.lineTo(e,i-o),t.lineTo(e-o,i),t.closePath()},ellipse:kt,ellipse_vis:kt,hexagon:function(t,e,i,o){t.beginPath();var n=2*Math.PI/6;t.moveTo(e+o,i);for(var r=1;r<6;r++)t.lineTo(e+o*Math.cos(n*r),i+o*Math.sin(n*r));t.closePath()},roundRect:wt,square:function(t,e,i,o){t.beginPath(),t.rect(e-o,i-o,2*o,2*o),t.closePath()},star:function(t,e,i,o){t.beginPath(),i+=.1*(o*=.82);for(var n=0;n<10;n++){var r=n%2==0?1.3*o:.5*o;t.lineTo(e+r*Math.sin(2*n*Math.PI/10),i-r*Math.cos(2*n*Math.PI/10))}t.closePath()},triangle:function(t,e,i,o){t.beginPath(),i+=.275*(o*=1.15);var n=2*o,r=n/2,s=Math.sqrt(3)/6*n,a=Math.sqrt(n*n-r*r);t.moveTo(e,i-(a-s)),t.lineTo(e+r,i+s),t.lineTo(e-r,i+s),t.lineTo(e,i-(a-s)),t.closePath()},triangleDown:function(t,e,i,o){t.beginPath(),i-=.275*(o*=1.15);var n=2*o,r=n/2,s=Math.sqrt(3)/6*n,a=Math.sqrt(n*n-r*r);t.moveTo(e,i+(a-s)),t.lineTo(e+r,i-s),t.lineTo(e-r,i-s),t.lineTo(e,i+(a-s)),t.closePath()}};var Et=i((function(t){function e(t){if(t)return function(t){for(var i in e.prototype)t[i]=e.prototype[i];return t}(t)}t.exports=e,e.prototype.on=e.prototype.addEventListener=function(t,e){return this._callbacks=this._callbacks||{},(this._callbacks["$"+t]=this._callbacks["$"+t]||[]).push(e),this},e.prototype.once=function(t,e){function i(){this.off(t,i),e.apply(this,arguments)}return i.fn=e,this.on(t,i),this},e.prototype.off=e.prototype.removeListener=e.prototype.removeAllListeners=e.prototype.removeEventListener=function(t,e){if(this._callbacks=this._callbacks||{},0==arguments.length)return this._callbacks={},this;var i,o=this._callbacks["$"+t];if(!o)return this;if(1==arguments.length)return delete this._callbacks["$"+t],this;for(var n=0;nr;)R.f(t,i=o[r++],e[i]);return t};q({target:"Object",stat:!0,forced:!s,sham:!s},{defineProperties:Tt});var Dt=i((function(t){var e=z.Object,i=t.exports=function(t,i){return e.defineProperties(t,i)};e.defineProperties.sham&&(i.sham=!0)})),Mt=function(t){return"function"==typeof t?t:void 0},Pt=function(t,e){return arguments.length<2?Mt(z[t])||Mt(n[t]):z[t]&&z[t][e]||n[t]&&n[t][e]},It=ct.concat("length","prototype"),Bt={f:Object.getOwnPropertyNames||function(t){return dt(t,It)}},zt=Pt("Reflect","ownKeys")||function(t){var e=Bt.f(A(t)),i=ft.f;return i?e.concat(i(t)):e},Ft=function(t,e,i){var o=m(e);o in t?R.f(t,o,d(0,i)):t[o]=i};q({target:"Object",stat:!0,sham:!s},{getOwnPropertyDescriptors:function(t){for(var e,i,o=g(t),n=C.f,r=zt(o),s={},a=0;r.length>a;)void 0!==(i=n(o,e=r[a++]))&&Ft(s,e,i);return s}});var Nt=z.Object.getOwnPropertyDescriptors,At=C.f,jt=r((function(){At(1)}));q({target:"Object",stat:!0,forced:!s||jt,sham:!s},{getOwnPropertyDescriptor:function(t,e){return At(g(t),e)}});var Rt,Lt=i((function(t){var e=z.Object,i=t.exports=function(t,i){return e.getOwnPropertyDescriptor(t,i)};e.getOwnPropertyDescriptor.sham&&(i.sham=!0)})),Ht=Lt,Wt=!!Object.getOwnPropertySymbols&&!r((function(){return!String(Symbol())})),qt=Wt&&!Symbol.sham&&"symbol"==typeof Symbol.iterator,Vt=Array.isArray||function(t){return"Array"==u(t)},Ut=Pt("document","documentElement"),Yt=n["__core-js_shared__"]||function(t,e){try{L(n,t,e)}catch(i){n[t]=e}return e}("__core-js_shared__",{}),Xt=i((function(t){(t.exports=function(t,e){return Yt[t]||(Yt[t]=void 0!==e?e:{})})("versions",[]).push({version:"3.6.4",mode:"pure",copyright:"© 2020 Denis Pushkarev (zloirock.ru)"})})),Gt=0,Kt=Math.random(),$t=function(t){return"Symbol("+String(void 0===t?"":t)+")_"+(++Gt+Kt).toString(36)},Qt=Xt("keys"),Zt=function(t){return Qt[t]||(Qt[t]=$t(t))},Jt=Zt("IE_PROTO"),te=function(){},ee=function(t){return" + + + + + + + + + + + +
+ +
+ +
+ + + + \ No newline at end of file