public inbox for [email protected]help / color / mirror / Atom feed
PATCH: Graphincal explain integrated in sql editor 10+ messages / 3 participants [nested] [flat]
* PATCH: Graphincal explain integrated in sql editor @ 2016-04-21 15:08 Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-04-21 15:08 UTC (permalink / raw) To: pgadmin-hackers Hi Team, PFA the first patch for graphical explain integrated in sql editor. Below are the few things which are different from previous patch which was sent for stand alone graphical explain. - Now user can select Explain/Explain Analyze with four optional properties (Verbose, costs, timing and buffers) - Initially graph will be scale (according to only its width not height) to fit to screen so no blank space will be there in case of very large graph. - Along with zoom in/out button, "zoom to original" button is also provided, by clicking on which graph will be scale to its original size (not same as initial one which is according to screen size). Please do review this patch and let me know in case you have any comments. Regards, Sanket Mehta Sr Software engineer Enterprisedb -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] integrated_graphical_explainV1.patch (661.5K, 3-integrated_graphical_explainV1.patch) download | inline diff: diff --git a/libraries.txt b/libraries.txt index cd01c24..c337881 100644 --- a/libraries.txt +++ b/libraries.txt @@ -10,14 +10,13 @@ Modernizr 2.6.2 MIT/BSD http://modernizr.com/ AlertifyJS 1.1.0 MIT http://alertifyjs.com/ CodeMirror 4.12 MIT http://codemirror.net/ aciTree 4.5.0-rc.7 MIT/GPL http://acoderinsights.ro/en/aciTree-tree-view-with-jQuery -contextMenu 2.1.0 MIT https://github.com/swisnl/jQuery-contextMenu wcDocker 0f5690318c MIT/GPL https://github.com/WebCabin/wcDocker Require.js 2.1.18 BSD/MIT http://requirejs.org/ Underscore.js 1.8.3 MIT http://underscorejs.org/ Underscore.string 387ab72d49 MIT http://epeli.github.io/underscore.string/ Backform.js 5859b4f9db MIT https://github.com/AmiliaApp/backform Backbone 1.1.2 MIT http://backbonejs.org -font-Awesome 4.5 SIL OFL http://fortawesome.github.io/Font-Awesome/ +font-Awesome 4.3 SIL OFL http://fortawesome.github.io/Font-Awesome/ font-mfizz 1.2 MIT http://fizzed.com/oss/font-mfizz backgrid.js 0.3.5 MIT http://backgridjs.com/ backbone.undo 0.2 MIT http://backbone.undojs.com/ @@ -27,3 +26,4 @@ backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all +Snap.svg 0.4.1 APACHE http://snapsvg.io/ diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index f461cbe..e2c10aa 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -9,21 +9,45 @@ """A blueprint module providing utility functions for the application.""" -import datetime -from flask import session, current_app +from flask import url_for, render_template from pgadmin.utils import PgAdminModule import pgadmin.utils.driver as driver +import config MODULE_NAME = 'misc' +class MiscModule(PgAdminModule): + + def get_own_javascripts(self): + scripts = [{ + 'name': 'pgadmin.misc.explain', + 'path': url_for('misc.index') + 'explain/explain', + 'preloaded': False + },{ + 'name': 'snap.svg', + 'path': url_for( + 'misc.static', filename='explain/js/' + ( + 'snap.svg' if config.DEBUG else 'snap.svg-min' + )), + 'preloaded': False + }] + return scripts + + def get_own_stylesheets(self): + stylesheets = [] + stylesheets.append(url_for('misc.static', filename='explain/css/explain.css')) + return stylesheets + # Initialise the module -blueprint = PgAdminModule(MODULE_NAME, __name__, - url_prefix='') +blueprint = MiscModule(MODULE_NAME, __name__, static_url_path="/static") ########################################################################## # A special URL used to "ping" the server ########################################################################## [email protected]("/") +def index(): + return '' @blueprint.route("/ping", methods=('get', 'post')) def ping(): @@ -31,3 +55,16 @@ def ping(): driver.ping() return "PING" + +# TODO:: This is a demo url, remove it later. [email protected]("/explain") +def demo(): + return render_template('demo_explain.html') + [email protected]("/explain/explain.js") +def explain_js(): + return render_template("explain/js/explain.js") + [email protected]("/sample") +def sample(): + return render_template('sample.html') diff --git a/web/pgadmin/misc/static/explain/img/ex_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe75d909f5092c4d3ba8978c75fbc57d7f606d GIT binary patch literal 574 zcmV-E0>S->P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10lP^=K~!jg?U_w#!!Qs=pNrR76nc`JAiEyfyPUu$F?5lg!9`tE zrVdorjI6O#*B=N1Q4~GTk7uODImZ$7QhEcqbb{2T!+^AsNlnvqz}0v!OZCpVcg+u) zSl03oH-ylcGy!)Fj09u=UN>$mMIX+&H|b<ajP!gzp{f<N2t38e1(}OYz(X)^Z9SDm zaL$Pb&;cXx85twc3D+9}YYwWtX(n61tgLAZVhA&A0ZDox`m}f_o&;Lp=3^|TZAm4? zB8D-uw2Hk&77xL~GD+H8Yh{L+-D~onRU64N$mC{z9Z`Z<4$%uyDn(tUuBBqiTE>@* zne6>YDVVIT^|Y|u&2%+YKxQ4H!ZKN8+Uk0kwJKPjW&<(>@$PjAe4RCOnSn%Nr0(=P zYi|fJ04V_hnL$cH0K3&%;sz_V=BgQD)cm$)2vvhs6@*_isdrBfc8kD{yg=7gktITF z+PGFu2!0OeLWgu>5LFp3D9xourL!bQu%a?wd{rRqFIvi++{=Q!&>aaV%KTa{dS;2c z$5o3IhEOTyT37x61pK30-JX4KbAS7Pk<5;R_SRus>jbGyCrEAj0!#X?PWurOy8r+H M07*qoM6N<$f>VU-$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_aggregate.svg b/web/pgadmin/misc/static/explain/img/ex_aggregate.svg new file mode 100644 index 0000000..198bf04 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_aggregate.svg @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABWVJREFU +aIHtmU1PG0cYx3+z3vViMAYcTIINCUE0NBRqkElQIhSpbS5VpUg9VJV6zEfoMR8gp6pfoOf2A0Sq +0kuVS0QEwYoRhCSQEt5Dg8H4hRd71zs92ItppZZdsKNG4i+t5F3PzD6/eZ55ZnYGznSmM53pQ5Jw +WvD+gykZ36ylKRXFQnDvTtSxbeAQ5OFYQv68rNPc08Z81gTAA3hE6VIBRRHle3H4XFPEYTm1/Myj +CFQkHiFQlFJdu44qoFlTWFhM0e1Jc/f2oGMY1UmhoA6FvImwJOmCZGnXJGdaqOWXq0IQ1BUuNagE +vS46Ugr2ihYHRYsDs0hRQlD3EGrx8WY147wdpyAjsUHx469TcvLlWyKGxcXeMGObeXZN67BMk6bg +W9hg39Xroa25jvbWevQmH0nDwpQSTRHsF9214yoOoTJWvL3tPEkW2DWtQ4+MhnSSM2uuYvzB44R8 +nRZMbikM918gAwTMIutLf/LDN87HieIW5N6dqIiFoPDqLaMhnWat1ETGsHiyecD5/gjxzRKwk/bu +jA6K77+KitvhIpMzGwS9Hnw+jZ28O7tcg0AFZv/lOjdDOn611HFZUzKezBMecAcDcPf2oBg+Z5F6 +l6WpXiP1PkCgApN7sc5oWx0B2zOmZGK7QGfUPcxQq2RxYxfd4zriTw4CFZjM7Bo3WnUabc8YFhNb +Bl3RDlcwn40Misy+QYP6nkGgApN6vsaNUB2BshE5o0h8O0/PkDuYywFYTe5zOeDOjlODQAUmObPG +SKtOYznMsoYkvl3giguY4ZDk6fwWwyHHEQmcIP3+l+zUHB6IEE8Z5E0LTSnN1tdadWbjK45S88Ox +hPzypvNZHaoMAhWYzmiExHaBg6JEFdDi9RALepl2CONWVQmto7LDbGVqjVhQx2+HmWkxncozeK3T +dTZzoqqDQAVmcWqVWNCLX7VhJFMpg+EawNQEBCowr5+tMhT00liG2TOLTO8UuH79YlVhagYCFZi5 +Z6sMBr2H88yuabGYM/jui26q9Y1TUxCowMzGV2jzlRbbDapCl1/jl98XiIWq8x5Hy/hqql71MNCs +MTGxXNXsVXOP2Om4L9ZJzrSItmhMPq1+Cq76PHJUNsSVoQ4W94r0+tUPZx6xZUP0DHUwnzXpqSEE +1MgjNkRXtIM/dk2uNqrMPVutGQTUwCNHlyhzGYPe9wABVQY5umh8uWNwJaDx+hQQj8YTjifLqvWQ +DXG+P8Jc1qC/WSutt04Icf/BlJzPaXzkNxzVr4pHbIjW/giz6QJXA6eDeDiWkEt5nW9vXXQ8858a +xIZo+STCq3SB3iYv69MnhwB4kRJ0tzeynNxz/KV4KhAbItAXYTZt0Nvkdb2v9U/9NpaQk1sKoVAD +eVPi8zird2IQG8J/NczzHYO+Ju3UEOPxhIxvCqLdQXKGxXbmgPZ6Z+P9RGstG8L3cZiZVIFPgzqp +5yeDeDSekDt5eJMV/PQCOsPNKI115C2JYVjUObTw1Fum5zRB10bSbTOH8vs0AvUqoRYf/sY6MkDG +hPY6heWFLT4P7vH1reO/31155CjE42SBnGGhCYX0pTaCusf9sYIQWFJSlJJs0WKrYGFYpf90xcNW +Jk+405ltjkFsiIa+CE/eHZAzSjvxO4ZFLi1RFfPwiEFTSoZrR36risArQFVAK5dTlcqxhHoEVhHg +9QjyhsVIzNluiqPBfhRiamOPbUNiVnXr4O/yegR72byrTbpjPWJDeHrDTG3ssVoUFKwaUlD2qnA3 +fI8FiW/CwPVLzKYNIs06F8rPa3X0BqUNvZW1NN2NzjvsWJBYCOITSwD4/qWMBIrlq1qKhSAWqWKD +ZzrTmc70v9JfbO2FoTKhMLgAAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_append.png b/web/pgadmin/misc/static/explain/img/ex_append.png new file mode 100644 index 0000000000000000000000000000000000000000..017a2068b735f13cb89a3bcb2832e5880d17df56 GIT binary patch literal 1162 zcmV;51a<p~P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(LcQrnzUg(&?|IPgRl@0p)bM7=>}tvEZ_4YI+3|bM?Sj$mrrz?7)b5hj z@2}zW1*hRn!RZ^W<6Fh+V#n(^x8+d2=WEC4a+aaNk2du1$nfm9@9MSh>9q3g#qH&> z?c}iR<FN7S!|>?B>));G-mL1~tMBB$>*k;D>$d6On&{t|?&h=S+m`0ol<eWI<I<1f z(2eQZsp{jL=-rs*){^1Oi|N^?<kgYn(~#oMjOf><@94Ab;k?JHb@1lE=hUR;)1&O& zx!}r)-o=I9!-U<zg67eo-^hpM&!OhgqTIiL<j$Y(=D_CCqwCqW<jtPr%%0=Rp4+{D z+PZy)sbo@(8Kui)sL*Ju)oiZXakAicwdHz}mC<Hv(aX&7yuR$dzwOS>^3l=q!NTst z#P8G8^VQY#$jI=?$??j|@!8t--ro1u*Y)Ay_q@IAr>W+ss^`DI?yaxsud(UH#qY<+ z@3pq;x47%Lx$M-`^vB2WiI(>{00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0zpYcK~zY`?U3tJ5>Xh&?SzGeqJ$LLD=fGO%SB*ek((>YO)i2W3vOk#CSYi4 znRfSIZ+9mfuyZIJXZldjhj-?kd4K0Q&oeUeU#e~(MZ}3i&`phI^cK3U)oRDk*qyt& zaWp=m*H5C!DTCo2!Xg@@(Kw2xO(xTQ^uTO3>(InQtyYhwW@dB-G{|N8&s`p=e<n^G z0<#v2W%goPDar;m`yB0nd8dnU0~WD(JRXZWy+HYV3x2Q%f<YFXp-`9`j6@<<8Ch7g z109S;oxp^{vG^dw8;L|H@Gk}eG_cV`k^ych7US{Aj}#QOtfZjT6pWn09q0KJ7I_Sc zh!gMP^;&1a=J(qj;9yzj3b;8go`O_5oyp=qCa3T%U!+JRLvo5(EXPASzgj5bk-lP+ zO0n@=u9Sw%YN1djA(xBgOQn1U)(VwM6_42b_BpvF*6CW8Q^eI2nT;%D%hhV_+8T4v zEISV?48yr0#q(+T{k3Ab2DQz)fOi2p8cn$56iaG~e0~Fpl}e)u^=7jv;1M>FxKwPp z(r9dgKt_How%TaO#{-achU4Ux__UIuSXNThl@v8W5U#DUt7}W#B5ow&NzYaPMkJm- z`+3#B5v1H~KNqnZ(M8-Adt7=qvQOWu;_p1vqZcA^BYthzl84euNfB}45NYSt?ruwJ zclP#POWpm0H;2+;tKB}5j=J6Bw-Oe4cXIOnRO+0aefTJS`uyeVj?_BsblTFl^ZkS4 zzljW=<qD1clll(R-{b2g;$(6F001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@z zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUh cIxsdXFf}?bFv^!ztN;K207*qoM6N<$g1#AbUjP6A literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_append.svg b/web/pgadmin/misc/static/explain/img/ex_append.svg new file mode 100644 index 0000000..4f2a827 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_append.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABb9JREFU +aIHtmVtsFFUcxn+zO7NbttAtvQEBjUaiCZRLIzEhMfJgTIio0RJRRAkk6IMkIEHAmJCQGFHBBsQY +fZBAjMgtAkEgRuND1YSEcKf0AVEuUlPphS7b7rYzs3N8OGdmZ9tCZ5eWGOiXbGbON+ec/X9z/v9v +zmRgGMMYxn0BLUinVd8dFfVXzT78rAcjDDW/8bWZgWLUg3Sqv2oy85kpnOuwADA0mFoaof6nszw9 +eyoXb2aDqCmLcuDQGV58bhqXO210DQxN8Fg8wvb9p1n00nSaumyiYdl/4iiDzXtO8c68GppTNnpI +xv1Asc5HO08GCS+4EIBzHRa/Xe/uwzckTE62ZYVEwiEALiYtGjv63uWmLpvzHSaGHsrhm1M2fyZl +fz0cDhqWh8BCppQa3rm3IkB1PAJAkUqAyXGDP5B3Wte0nBU5Cowvln/pXxGAsTHJ+1dk0IU8WXKZ +33/O5eoV/8uPufwVxR84lMsfVfz2/f3Pv3lP//yxIAESsNjrNz0hHl+8Bdu+4XG6PpoT25ZxO94y +20AIAML6aE59s4KahZuwultBCIQAI1rO6R0rmTb/U6x0i+IFRrSCs3vXMGvFscErdgDbvoFlNg/I +CxW41dOKmf7H4yJRxXe3YqaaEBlHDnDk0Uq30J28Kvs7TvZ6QOSXiLeByGTUjCKXFwIcgRAyMOEI +RMZBONm2PPo42wFxl4UIIbIiJCEPmf4DRgXsCXSvZxzVFrn9AyKwEF0f3W/bMMq89EAIworXo2UI +4XgBGdFyxVfIVVFjjGgFAJFYFfj7x6ryEhKokI7uWSXMpvo+fGT8LIaanzlv4+AVu9lUL13IapeE +EBiRck5sW0bNwk3YPe2KdtCNMk7vWMn0BXXShZBpYkTLObN7NVNf/gQzdV3N46AXVdKw732qa9dj +JpvVPIJIrIrzB9cGCS+4EADLasfqVi6Ucbx0snvaMdNN2VwvUu6UbqG7829V6NlUMlPX6b6Zdaci +lUpmspl04kq2bpyhKnafJcrAUOdOrl36i9snwrsu/AaQO2dO8eenI3/XysdOHeVmfjsVvZzKfe64 +IrxrQ2W/YX00RkQJEALdKJMTGGUwQrmNEOjKnYxohbzbKiC9qFLysaqsAKHcCoiMHCNFqv7R4jF5 +Cbn/XGv6gjqsnjavBvRoBWd2vsu0VzZguu6UcYjEqji7dw3VteuxlDuJjIMxopLzB9cy+YUPMDv/ +BWSdRWKVNB5Zx6Rn19HT2SyfpwKKSsbSeGRdkPCCCwGwetrocfdCQhBVRWq6eyT3qaxSw0pdJ524 +ki1m1506m0m1X/I4N5W6k82kFV8I8nMtb/vR69z2uZDj471th7/YyRHmbmnIb0dSuJDBslP/tkW6 +3Z0JyFuIHi3PCdR1J72okiJlwQDGCOlOkViV2iCi2pKPFo/xrYasBcgeXfRuD4R7xrWG4WL97iWi +tm6cWL97SV7lWui4WyE0cJfbB3P82mHmPjWH49cOEzSoQsfdDgUL8QcTNnTmz54bKKhCxw2EgoX4 +g5E/g0Vz3+D4tcNDMm4gFPzOPmPCHL7/Vf7568+/yrc/7PL4fXw96OOGHLV148TBy6tFbd24vFKj +0HG3wh0Vu4uwUdjCFjquP9yxkBkT5rB11zZmTJhzV8bd8wj0+N/yxRnR0NiXr54EQ80vWzpt8F6s +GhrhzcUPkbhpEdLkvKVxg6+2XmLpWw/TkbAJqc8BpaU6n3/5F8vffoRk0kbTNLQQxOM6dZ9dZOXy +iXR1ZnA/gYwaZfBx3QXeW/ko6bR8xw+FNGKxEB9uuBAkvOBCABIJi5ZW+SFG0zQ0tZgdCZvWNksF +AEoPN5MW7e02oZDqr/iuzgyJhE2o17ecVCqjhMv++T4ZBsW1/g+4Z4QEXr943AANr0bicTm0VB3d +GilR7ZJRBhqaVyMlJZIvHilzyl8jALFY2Es/t0bywT3jWsMYxjDuE/wHgXPsJYG48XQAAAAASUVO +RK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_and.png b/web/pgadmin/misc/static/explain/img/ex_bmp_and.png new file mode 100644 index 0000000000000000000000000000000000000000..64d5869dcfcf9d94d031fa068cff93ea929180b2 GIT binary patch literal 1006 zcmV<K0}=d*P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004)P)t-smD2kF z003rd(R6flb#--ic6N7ncY1nyHi*G{dwYC*e13j@fPjF4f`WsCgM@^HhlhuVh=_}e zi;azqj*gCGmC%omkC2d%k&%&&j=z$UlEIHQm6er`lHGcqshOFXoSdAVo}QbW#Gjv^ zrlzK+r>D86a;T`NPQK>5s&lKWtGldpyRCMut*u(Y=dP}<ys&q#udltad8@4GzOs6W zx!ba`vSh{Rx3{;mwCZuo?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?Zd;v-NJ*w!S2S! z#*5VM-^PaD$cK{E@5aaP;L3^0%F2}3@Z-y#<IJAq&7R`WjpWXs%+2x5&hq8Zq2|$| z)6>(Y-ty(vljhW<)z#JK)upZ9^VHPy=+~y`*Qe^(w&~ia>DsB<+S=*ds_NXT>)W{8 z+}z#W-Rs`0?A^KE-rnrst?b~g?cclJ-uCR`ui@e0?BlTF;^Ob*zvboS@aDkq=fUUa z=jrL`@$1Cu>gw?D@bU5S^78WY^Yiuf_4fAm`1ttw`T70*{r~^}C9&%N00001bW%=J z06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0q;pfK~zY`?UY$l6G0S(b8}-Di3kcP z+Oo)^h$4bwltoqvL?DD{Mjf_nBqD~O2?A~ymixDzo*9a*Gm})MC?7Zv{c`K8Gv{>Q zvDq$ko~o9(s?QF(wL!N4k*52GJqwax@WJEtiUu~Rr}eShD?&VOcaK*pj!Vugb=sg# zfY{%@e)DeKes;iqrqk&yCPD_D!r-C^Nk4<GWMRlx_z0E==`xVDE_fnFj<OJC>PwuJ zQ#!=9lF84TBBa*NRjVOi9LP1IA^nW2-@@fKw*1L<;8opaGaip`h_l>+MlB1G6SG9S z=+u$;BX}4UBk&Ro<O=>E`h+(O1ZE*><<f@Dv{HsEI<ou#?nSH``|ZN(SURV-%r>Ht zNXoo1qP+&hYdgl><kJ{stMHBkrzooyKsJ^Ng_cqlS=#YAjp3zO3@bPinuH0(v@xPG z-th~(T!n2MS(<=x#ngpg%P%#>ef9pot6A9mcrN5H3(-xi$?R{pAeQfQB&8_Is%c|H zG5v{QDc(Jx{2HTgO)iJ4;r-tV>{PR?%CelW*cUn`^~2;*7z$c$rLkbz!Q>%$6)bF# zgDMhW1^r<X!9XBkv6Uy4*H)f(3HbeC^EY-H@%KXSjQLiI5MN;~GdYo*S;9V_FI=R? cF7zMiA0?@qIju>9W&i*H07*qoM6N<$f<qfLO8@`> literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_and.svg b/web/pgadmin/misc/static/explain/img/ex_bmp_and.svg new file mode 100644 index 0000000..4498984 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_bmp_and.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +kmj4Fzs2o2mBbQUEAAAAAElFTkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png new file mode 100644 index 0000000000000000000000000000000000000000..2657d8c39328bfc80751c60db9d3ab4341c0de35 GIT binary patch literal 1106 zcmV-Y1g-mtP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s00000 z003rd(Nc{WHi*Gol_FY@Wn`8)38~@|tKwvp&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPGu5^~NHbTAWN5AP#zUE86=}y7vTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q^_*?AyJGyuIvu(eH!N?S#?pz`^c> z)9|d;ZHv_Ik=5>!)$gv_amL5*l-Tf>+3~XAcCFUw%+2wj+wtexE9lxP&Cc@b+bZna zD(>4V@7yZ!+$!?iD)ihcx!dfw=Y00vDy`r1`Q0h{-6_=6^RD3Y``#)1-YNdxDZbwA zx$A$x-|oWT?z`@S?c-qY<6p($@9^Ybyzqqb<X`jTU&rI{$m8(y<zMvWU&`a~_2pmp z<zM*aU(4k2-rn~3=3n~eU(Mz6{N`W&=3mk0^3&+^^6H1w>GRa-^z`e8*6H;2>xcO3 zhu7-$`s|1O?1ujAhT-q`mEcQQ00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94 zoEQKA0&7V`K~zY`?Ud_N(?Ar(NfQ+@uBZsUQR*A(3k7^uiA_xlwb7<XX$T2Wl46zw z3Z<omf1TZggd}Y;GR`=D;C$H3?B=&;&b@cGr{_ffM12%iU&sC(Yu~pzN7RRBuO_}z z9SHSg=<4;C)SHp}k3Ldg#wI3zy8lp*uid=+whJ=U+k5r~HGFAc;3+jWJaTW6`U{t^ zEElbP-|8I2KEHnd^>^&(-vmu3&<E7Y<#G+wL{Y4Rx+F<;;36;16PJH@5PE-~#z=W; ziYWt;VNw#1SeBJN2=S2cA-lUa!Z3^o#8j#a5_H+w@gP!)Wi2G_L4sKv#G9fn%W}g- z`eRt9$y)*BIl%I*K9?(GoOF@xZQI4ZUy^0CDl3(yC(CW(0vV5!j_A!z8h-}~mT*$6 za2%)l5JX@-7#$sd_le%vpcj!ymO#PfbULko3dd#C2p5DnE;2^GRe;K6G8zcaf)Jd= zPSH>*C`D7%v}T}UXUKCdvcCQ&74!AQMsP2b2D)EWk&C8PTM^wqM7$}qY%Zrq%-GtR zg(zuUST%!@YA%<95iYB%7Gn28&1ADxp!<=IEX&Il;!V+l5Vj&_Y-#D(Gq$jB=z@FE z)OFo<X@_?I6h_E^1__=pLT79oBQrC<=I0lWMDj$zh?ucbsf$a&>(Y@0AyyV$hfa#N zVHoX*8Jn9s_Kewxb3cRzb}`Mpu<oOWZ+aR(egNk4c?ck1K*3ExD4Jn2MsLj~le1g2 zh42s<1wlYavFJkrE~R9$WV`UZ0SrM9%pelTlE5>D9%WyOJ=2@Tu2_G^GagZ~6a9ZW Y0Mz-{B6#`Cr~m)}07*qoM6N<$f){{JGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_heap.svg b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.svg new file mode 100644 index 0000000..0f061a0 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_index.png b/web/pgadmin/misc/static/explain/img/ex_bmp_index.png new file mode 100644 index 0000000000000000000000000000000000000000..23b9733b56792533e4db25ca9890a0a0140c6ff9 GIT binary patch literal 1172 zcmV;F1Z(?=P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004@P)t-s000{R z003rd(Nc{WHi*Gol_FY@Wn`8)45{LDla^$a&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPPu{MmZbjzYxL%irozv)iC=1#%sTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q|V#etORA+r5d~zJR>F?0eDg-NAx` z(d~rM?%l(Kz`^c>)9|d;ZQjL&i`4Gl$A^*C?%>FXlGX37+HuCm@8HUbl-Tg$%!-%U z@#4;m<IJA2;C8Ln>CDaX<<6kv(T?ZZE6vXG=Fy>}-SXtrk>=B+^4u!t)TFuF?6>E9 zt>5$1)bp<3^XA!==+~zI-YMzWr@r3px$A%D+?T-L?&;d7!r<=c-k9s!x9Z%g?c-qY z<6p($@9N#Gyzqqc<X`FGo9x}X$K&wG<M7Jk@a*8N%jEIi-uC(CU(Mz6?BlTi=3nmO zz3t_((dY8+=Caf1^Y7)q^6H1w>GRa-^w#P0@aMtr>9p7C_3`P${_KYG?Z)Bn_g>Mo zbpQYW0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_00N9jL_t(Y$L*BsQxZ`a zhh26nvhB^vO1oLo-JmFv5|N5XBA|_nRxB8D7XcMR7F@v#0{+$QVK1_a?Bq1l^uhPT z*_pHZ%x|7^ezOAuC-YBckU%rovwx?vFI&Y|#D{0EroRzA2=QcObo3?hX8iu6kHpu> z>6stWH^k%XH}AeZ0vXY2wKs^dOT)uYiOI3?do#per1Wz++u7&Wi~K6S(tLjX{>v}T z;kSB{)N>E0r_<>=v>S~^8`><(wn0K(oX0MI??T9f0}>%=uh*M~Mn0c!0Gmiet6d28 z5R)PM`wD~wHX4nVRZ@0$Wk@2yLNyu+bs<U@5fNNE7R_?GyeA<;8Z@WzTMFbFpyAi& z{3=ViitBI*+1Zh$RI5#B7K_EbE|=Tb1ze}Y#UZ!0Nc6mdd9k!$QS|wISsB6+XdX;V zOuhR=Zf=sx+~8h})31g?q2dvUJcUEVlnj&w#N$ape-{qnT{4-vU{TAaQZ>biox#sZ z$i~K>oS5uhcm(RXT&@m##cZ|)wNxxtQMr8q$pr#|oL~`iI2^P}$JW;+qy$+HkJ#<B zO3K=rgfNiu%+AIjVz=9ZDji#0?I5jEsnmj63|UlYnl7kxY-Q!x9a~xwQW&NMl}LoH zKp`0P7y91*DTMI1AI2EY!p2zyEfzD?w_{TXnV<i;jEAu>1GLR%4T9fnRv_|@#p7Km zwAE@sh{;5$bc{nfE(~(vEeaGxB~?1MxOnW2@ran>r>FuX-EMcX-|cfhzPUN{^8+Rv z=Ja_Bx6xp5_UjnAz2I^!Y?C5FnM@`(xD9edkrH>g;)f}e$!P3B6fSzyF}>u%TO^%M mr}D&xdVb?7Cw4Ob-~0w&gyX$CR{j?N0000<MNUMnLSTYde~VB6 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_index.svg b/web/pgadmin/misc/static/explain/img/ex_bmp_index.svg new file mode 100644 index 0000000..4b52956 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_bmp_index.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_or.png b/web/pgadmin/misc/static/explain/img/ex_bmp_or.png new file mode 100644 index 0000000000000000000000000000000000000000..c22fc31eee32e53abf634278f9d57751181f15c0 GIT binary patch literal 685 zcmV;e0#f~nP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700030P)t-s00000 z003B6SY~U{Hi*GwmC%ijzrl|-kCNSbo~fFenwy-&xu<eYzUI5CbGxi`yRCLw!RNfN zcfGNBtE}k0vU-WR+hoP)v$X2Ey1H@8?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?cKtI zz`^c|)b8KLhTq7ClGX3V$M4|EiImvz<IA4o%%0@Up5oAr<j$YW&GF67^3l=J<<Oz# z(W0i_^5xc(=G3I;)upZ9^VHPy=+~y`*Qe^(w&~ia>DsC3+^Xu_s_Wah>)x#F-MQ@G zt?b~g?cclJ-uCR`uk7Qn@8rMa<mB+?!0_k6@$1Cw?CkIF@AUNa|NsAqxAFG?0004W zQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkPM@d9MR7l6|)NN0KU=#*mj$o+0 zXGv;SRwxw`6%>^SK@x>8z5V~+lCW40^I>$hY<=+l#CCS=?A!_rGtXZp&xOfP4=T~1 zLLuDg&VhK#Q3h9{B+&*8S6f~eBpML~p(b&^vn6@U$0T2m#b{8Z5cd4&_~MEE7O~-9 zf*=_4G_tn|`*$&UE0u;Z3AUi@Ws_kpcNvpsxCSJ7EW-w!ByJ(e*z+DnG*V#06sAdo z57R(x899zKpx?3pi_}}3HCVOj1h#=r;0$csmirZ0vT%(JY|HXz-k5KiT_1Ogc>-+% z*I2g=Ed#gZrj<t0Z!rv`Kl8@=x~{vp_eDR1riLU<*hLa;LR4I1uBNJPc4P0=>MO1> z^3%t=s-pBVfBn$JPrOoxdMEQgMkXTi54I4blS&e|kfbNeaxb$nGU<)Y^N;cg@O4qi TF88uo00000NkvXXu0mjfLbGwY literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_or.svg b/web/pgadmin/misc/static/explain/img/ex_bmp_or.svg new file mode 100644 index 0000000..1588cc1 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_bmp_or.svg @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAA75JREFU +aIHtmF1om2UUx3/v8tWmDUuZjbVRET+QbZJ0VIQNb/wIu5mzUJl4s4s4vRFBVkYZgojidMMMQfTC +jAkiWCeBigMZarwRxerSJoyOOYbdNHHt0rUxadp8NI8XabNuS/M+z1y2t/D+rvIenn/OObw5f84T +MDExMTG5DWiyB/d8NCYS2cx1cZ9rPUde6ZH+nkYcPHFWREZT18X7t3QzuP2hhjmsskkS2Qy7+/yk +8mVaLRotFo3722wc/DJ2AyXXJzKa4rVdW0jmyzi0at1ep1Uqh3QjAOeyZc5li7RbNJxWrZbsZpLM +lzmTKQLgssuXp9TIAy4rrRZqb8TrVJJLsfydK9+IDNKV+Fzr+Ww4Xjc+0kAnhBArnzVt9df4tOci +HxwbrRtvlAMUGlk3rvFxsIdcbhG7XcPhsNDhtvJe6OyqmmubWI6t1sz2TIjBFw9TWkhfKdDaQXwo +xAG9+iT7AGB2tsSlS0W2be1gZqZEPr8ooZklHA4TDodJJpO650sLaRKjI9xxTx/x2K+UC2ldDSg2 +ciPMzc0RjUaJRqNMT0/rC4TgyZ0HSI5/yFPPviudp+mNKFMR/PD1frybXuX74UFpmZLtuN02rNZ1 +/PzLDA6HBafTolynbkGODfj9j5KeiCAqAqt9g5xONsHGh9v55OhE3fjNotvXT3xoX904Or4l3cjp +MzleDt6n5FqqpBIR/M8fopifqsVsLZ0kvtL/iSm71smTcbZt7SAWS0i5lirF/BTx+O94HtxFfGzk +qqYaoTzsA3uf4JvjU7y053HlImUJ9B/iwliIwHPvS2uUGwkd/pFndngIH/lJVSqFAL47NsC9PQOc ++GLvUkQfZdfq7fU31bXsLZ34eh5j8o+haoG2Nepa9QZ7TbrWI33vrNi1BLaWTk4Nv66rNZxrlRbS +LGQv0LXxBeYz5ynMTUrpDOhaAlGpVD9W5AYdjOhaFaHUwDLGcy2nByEEqVOfV59bO6V0hnOteoO9 +Jl1r8863KeauDLjN6WH8+Bu62qbfEFUp5iaZz5yn27+b+dkJis1yrVvC0lVfLFakJYZr5Nr/K2pW +rIPhboj2tjsB+Dv2KQAO111Suqa7ltvtJhgMAuD1ehue7fb11x3s2+5amqZpQggRCASuiq12PpWI +sGnHWxSy/9TmxN7Wxelv39Str+m71srCGzWxTOHfFPnpP7m7N0j+8gSF3EWp2m7JrqUtoZoLkL1X +GXDXUl+zAAPuWo72LhDw129Hq8+uLimd4XateoMt41omJiYmJib/h/8AXT+3etbbSJIAAAAASUVO +RK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..e99f57478842f61cf0582433b659d37f0c532d5c GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_@3?!2S6O@1yXMj(LE06{PXIHn!e64$cEXI-` zzhDN3XE)M-9L@rd$YLPv0mg18v+aP48c!F;5RLO&CtC9zP~dS+JaMn}cL58V&ewnH znS#1o7niJ>^>*TX*`QzgMdD7POzPaTo+w<9uwpLL)1F%W#!IqdhoMSxhwp~0@cf02 zhkMjmROfZc`EZ)w`S;|i<*e@Qr8gQ^@9R11|6Rc8|AQ9IRLjSmUOFeWtM)%%ZozPh zRpl$&!*g?h?ocgpjVMV;EJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0 rRpn4L<mRVjrd2{T7+8WefK*!<m_an0njX3asDZ)L)z4*}Q$iB}@40B! literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.svg b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.svg new file mode 100644 index 0000000..622ca78 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.svg @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAARtJREFU +aIHtmeEKwyAMhLOxNxvb+7+R+yUU0dYkp7mOfNAfhal3Rk3qRJIkSe7EI3j80ryb9bAZqah1sRo5 +MqUx2kjFbSjayIyBlq7m3UYswiuhEfEIF1HoezoHainNY+b9+ap+740Iaqm484m2wbI1fujbNLma +RloTWw+SF7Cv0KPcYyQ6ByU7MB/bTMvDdQSjEyISVWSYIiLi+D5ZmUfQwIrGaCOVrmbmPTKiO6Fs +e0TkPPJDvWxGtmz21fRMMOlTsS2zwy7U0CCP31BTrB9WRdveOhjsPuqi72l9qOWAjFaokZGQWdw3 +Kjs2KKJGo0yIS/ZXdB7QmKK+jW8xFYwi9yrjT6PHFBFX5YC8aVwF02RP4/47IkmSP+cHUnUv9QVV +5FQAAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_cte_scan.png b/web/pgadmin/misc/static/explain/img/ex_cte_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1d779372f7fd212d2096e7701b0f1af05a5297 GIT binary patch literal 1955 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_cte_scan.svg b/web/pgadmin/misc/static/explain/img/ex_cte_scan.svg new file mode 100644 index 0000000..6eb0efb --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_cte_scan.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_delete.png b/web/pgadmin/misc/static/explain/img/ex_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ca051cd5d01ee2f3ac17779b362999d82a9285b5 GIT binary patch literal 1129 zcmV-v1eW`WP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003^P)t-sKLD^> zTU+Qs2lh=8Hi*I5b0^MyED5RN(19;<mZ6f8lEIHQ*N;guwdHlD$Lf$-LA>b8qFCae zX-dH9$EtPXqi$Wq>SM<0Ysctl$n0**>~+oT+Pi++y?@)iiQK+`+`oW((eK>Bf`rlT z-NS=~)9~KJgx<x4-o}QE)b8KMhu_GEk=5?t$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc z&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+mlIGK+<<^tt)THOtrLN%f=Gm0!*QV&# zr{>z0>DZ^~*{J8-m+9K6>e;sG+p6o@x9HxP>fNgB+_>rBn(N-I?A^NS->vN4y6oVs z>f@a4-@EMLuI=Ev>g1j5;;-%DyzJw!?d7rW<i73ZvhL=y@8!Vo=D_dhv+wD(@aV$u z>B8{rw(;x4^6ka*?Z)%)$Yy(c-~a#s0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkV znw%H_00Om1L_t(Y$L*8bdl^v_#f8bG-PLL%nhMc~q#`mQ2qBD7)FomPgc62MQMdg6 zk3DnFFeXNthkjrCko~Zp{O0Vn_M*|e%s-g7lsHRO4WY~igJFl-+ccRDsDn>t^C@+@ zx4(Z*ogcZ~Uny0@u)e--pf-`3sE>NR-c0Qve4jen-Zs0bzx2v0yz^33L*QXJ96n67 z-|vrMEC|8~Mm*0Cfcyr)IFAhP?`wTY`?t5ZJrIhyTpRdgGF}BjOnw=S3Z#aS8bOKz z2)SI2hh{Q9MZQla-3-V`zlMK|wO1@6q@DYg<e?sq#VQh#$r!5>kiFpjXD)tV7tH|- zs+Ce#@?tf9p@%c(J&3b~b$3yv?^<i0Wd?NOY>az?FosdP&5vMEuU5Oz<v6Z0{jh=o zomQ*WZOAT~qKnHCa6!L6FYiCcNQh7@l3<f{sKzcYIN<z#Z+<Q&%wTg<1P9CGU@I5F zAO{7nm(GGl$rxFfd0BMP$!D`Im_IsL#iN4e&4xICNNma=3fVzdXx0akb}J=xi%ub* z??5Y^PBlQ;M@VO0uV|$Gl`d%HB7Jh~V&PGT0ag%FkH=9lh;qT8zW{lfrqhr*b~zs- z5-3Jml9U9SrB6;$kZ?Mkj5>n$=YC2mx@aL6sYC-BEW?yl5z?^_b4}Y?mYDns#}ztj z_&TfPMvVl^-a$DU3E!wMhWB5?9atqzKrRj$h&b%_kUD~kp+H#Yp(6@myWO?~!I3Hu z=Fs5?L&$Ek1=NvFHk)oKyp$u6@HJeA0)gu%65GN}d$-s()mK`n1iAvzJBEpt;U*Lc zp;rPv-<A4eq!>gQ2X<i-UHB{(%b7ZoaEZkr8pXlNh({e^(G{YSM(iRIu-Pm=I9ra~ vF;TQX(RmkF9*^hhiNtoF^RIlF|7m^$H0#Fus?kFU00000NkvXXu0mjfhwW63 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_delete.svg b/web/pgadmin/misc/static/explain/img/ex_delete.svg new file mode 100644 index 0000000..2b4f372 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_delete.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +Lf4Lm1DRiPrg77MAAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..acba49c4fbfd9b871444c9e8d528deda3a37dda4 GIT binary patch literal 1607 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 FV1m**ONRge literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_foreign_scan.svg b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.svg new file mode 100644 index 0000000..40f1a59 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.svg @@ -0,0 +1,75 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAACGlJREFU +aIHtmWtsFNcZhp+Z8e6Od70G7BobQjA0gI3vToi4JKjQAAIKaZJenJJQigohbSiXKK3SErWKGhSa +H4XSFoX8KsQhchEEsOVIGBBQGszNd3MxmAaHhjs29q735tnTH+OdtfGsbdZBRYjvz+y8e3bmfed8 +33u+OStNePGHPAwh/78JfFPxSMiDFo+EPGjx0AiJifaHBa+vFVsqr/bAF+WncL/xog/XSHfjUQvZ +UnmVGTOzaGj2I0v6dccNsbJlby2zZ+fR2NoBgIMAmYOtbCmtZdH8PE63BgCIU4KkxVv4cFcNv3wp +jysugSp3IEkSo+MU1m6v5p0f59HULrBKOj7cYePdT0+hmvCJWghAQ7Of0psdxvn8TkEnWwMcvOkB +Wc/cRYo+5nRrgKrbPhRZRpZkJEnHL7g0zrcEcMoakiQBVgCa2gWXXF4AJEnq/M48BiRk3BD9hqEZ +GTvYwn+ACfEWhqBjDgKkO2M4BWTEW4zfxilBxjljOACMiVNwIHebEYCRdglQjRkZZrdG5CJF26I8 +8ZMCUX9xaA8889vXud9446dF91Yjq1dtFOX11wCYlJnM+g0rjAtkxSfwwWs5+HxeY7zNprL1eEUP +3Gq18fGJSv60NBu/39cnbrFYKTxZxbolWdz2aQAo+Blki6XwZBWNJlx7FVJef403F6QB8Odt53p8 +7/N5cWsdXQCvgd/qJACQiE7S7/f1C7cL/Tq3fRq+ToFBLQh4InLts0Y8gcgFdj9CCEGH0GtBwd8p +oO/oc0EUQYEIij4v5O2IXrBHBBFCIIR+HwW/ORcRmceAXMtmU410cih6zoN+DKVN6Pxu3IvAYtGf +fLxVpUNohoB4q75SOC026BwvhMChRKYbtZD8EcPZerzCFP/4ROU94YUnq0zxbRU1pvhuEz59Cok0 +nZWXv2bh0/mmLhQJf3VCHq3+sJvFW1UKT1bx6oQ87vjChey02NhWUcOCJ3O6mcDgGEFR9WlTPgNK +Lb/fR0lxCS0tzcTG2nG7XXxxtoHWY0cYPTaTm1e/wmaz4Xa7+Ff9Gb78vBhJknhm1lxuXb9Mxb+P +0izHkGaTaLp8nYrDB1BjY3l26lSutfvZv38ft1xtWGMHMS43G80ZH5FL1DMSiv379lFc9Ek37PAX +J9m+5zP+um6tgbW5XNTV1bG7ZC/nKo6RkJBI4Ueb+Of27ZTtKaHd7abwo00ALH5jJS2KhZmzvsOS +l3/E68tXk5o+DpyReQy4jdfawynx/sZNzFn6Bp+VFtPW2mbgv/ntH1j6u3eRJIl17/2ewbFxXLhw +gQ5NY/KUyVitFh5LSjbGj00dzc0bN8jJyaVD07jQdIkYi4Xeom/7FUGEMPdyq9WGoijGudPpRIlz +oKoqfn/YQu0Jg5CHDuPYiWoAXpg/C0WROVFRx+OPjaDpfCNTJubR5nLR7vWQkTaamNYWUkeOpLy8 +nKSkJBKsMok2pQeHexAiTNMr5EJf3gk/+eWLF1Ky/gMK5s/h3I1bBl7ffIfvTXuWIxcvApCaOopj +5xs5cuQIAKNSRzFlyjPs27ePQwcPMX36dPLGZwJQVlaGJyGRQ5euUFR9mvwRw015Rl3sIdcqHxRO +3F+9vYaj586Tl5zM445YA5+VnUnZ0ePkp6QAcObMaRIJcrFR75peW/JTvpWYyMHD5dhVmTmzZ/Pz +xa8AUFFVz8LVb5E6KpU4VWFXVZSu5SVysfv9PnyE027kyFRSps9ifnYa7615x8CbLl1C9gZ4bu4M +AP6xtYjk5BRqG85w5epVMjMyAKipqcZutwOQlZnJV/+9TNKY0cTE2WnxtAP2iFyiTi3QWwtnfNgS +A4GA8Tk5OVy8f3z71/zlrRX4/T5+sfxN7MOSyJ86HYfDQdkBPb2qqqsYNDQJW3wcdfX1AJTtLeOJ +tCwcDofBJVIM2H5TUlLInzAZi8POmLFjyUzPAmDYmHQmTpuBFtSIjY2lTZN4KiONEeMzSB8/noTh +w7jV1Mjfd+xg1+clWC1WJkx7Drfbzfsb/saF2y18Nz+Hp+fM65NDv4T0Fk6LjWWrVrJs1UpDdEld +A3ZZYd7cmcybOxMAu6xQVH2agtyMbiv1zxYvJvbJiRTkZnDTq78OiKAg7uUfsKfmLM/npOP2BRFB +gSRLOGyRE2hAvdYnp6pNcbM2Ihp8T81ZU/wb77VeeSq3W+8U6pEKcjNo6WzrNa2DRJv5jITwF/Iy +cHk1435xqsLu6jPGjITCYZNNxfVLSEBEXlFb/V5cnjAxf1D/3NIhcdvd1mWkbsW3fBp3vB6DcMiF +XF6NFk97l4em425fkOZ2tzFeBB0RuQy42AF8MgSDQUJ7HFrX199+XK83Z+zP/WGAxS6EwEOQ0FLS +m4D+Xq/beT/eTEMxICEOJYaAzWIICPVC+jG8sofwOFUhlDZCCMOF9GN4sQvhqqoypMv9VNVsj7Gf +QiI1jNG4kFl70Zs7ldbWmuJRuVakqLz8dUQXuhsP9Ujfzx1vuBOEXej5nPRupqGqKqW1tczNzsbr +1V1RCIFDlSmpazDlYyqk68ZcoCOc95NnrhFdN+q6upAeYXfSeyM6Seh4T3fSXcjl0Wj2uI3xoXTy +er3cbncBoAWD+OTIb1amQsrrr7HspXFcb/dxs/PJvjg7laF2G5t3mj+RSNGjgLucmxVzt++FQAsO +YF9rUmYym3c2IMvhFxlZVti8s4FJmck9xpvZZ1+W2tv40NF3D++vpjOyfsMKafWqjWJH6UUWzE8F +YFvxxR77v3e7k+5Keu4L0dOFHDYZEQzjIRdSVZWELgIcqj4+wSqDM5xOCdYoeq2QmG3Fl4Cem9i9 +udPu6jOm+L26k1lhR3KtqP9WeNDiofkz9JGQBy0eCXnQ4pGQBy3+B5c18hoWJQ7hAAAAAElFTkSu +QmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_gather_motion.png b/web/pgadmin/misc/static/explain/img/ex_gather_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_gather_motion.svg b/web/pgadmin/misc/static/explain/img/ex_gather_motion.svg new file mode 100644 index 0000000..6d18a73 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_gather_motion.svg @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAACBJREFU +aIHtwQEBAAAAgiD/r25IQAEAAAAAAAAAAMCjASdCAAFkjjE+AAAAAElFTkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_group.png b/web/pgadmin/misc/static/explain/img/ex_group.png new file mode 100644 index 0000000000000000000000000000000000000000..8d5de31bc129a9abcf4a73e19a48739139f66271 GIT binary patch literal 1228 zcmV;-1T*`IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=(EA5f2CVejTwfiWOA0Fgt11U#9qOVHuUhw@a(tm>9z9h#qH&> z?c}iR<FN7S!|>?B?BK2I-mL1~tMBB$bEG!w=AY@{n&{q`?&h=R*_GtekmAse>DsC4 z<DBHxlHtsY>Di~^&Wz~SrlQAS@94Ab;k>5IWyh*@@aDkh)THLqqwL+ecBwj^wTIx! ziQdJ9-ou35!Gh+|q2I`d<<Fq3)@|IrfaJ}di@s3r=D_ROwzcJZ<IJAp%bvUMgW9`& zd$dE9%UpG!OlO!lj)kjcYthWj@w~q5zQ66y&+^gH^1{OI!^Q8@)brKV^vKBY$;t7` z%kkOT_1@n1*Vpyo;rG0~?5C;bsH*3`zwW@o?yaxsud(UH#qY<+@3pq;x47%Lx$Mi# z@y^cjz`^d+)bz*4@RF6$yGLoX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0)t6JK~zY`?UZR(+CUVB(*d`NQfXa6^~z!}1Oy^sF^V-vQ6PniB6gWpu~n<K z*4lmj>zxTpNrZFE={Y_9;C#4z;o;8n<_!#Ueg5^if#~TvJ0ZwowOV^nZ(o1^02;Vy zu?(WYUYl(Q4Gr7vw@^pKIx;e1MSTv3<2Jf8Iy!1WJp{L*;juA`9sTu|@d=i7GIzB* zcbx`ea%zfYVA|z!O*g08?e>7jJHz>4miG$*&>@5fk}cqxo11erraKf0N5CtJA`kxg zXjIZ8>{QT6K3YgD<|aru>;+DY$NeBgqlu&uVVO20Mv+K3EONld<MRSY3yFkmKo;vr z%VLRIaMZ#t5Q{)kmQw~~SwrptJzZxz;S5eXn_Jw|;E6=MKJf88zXAbCN~R#CDCt$u z5zCqTb(dHyv_vdKafVpTQ;S3*D}%DOp38&oS{ZE#LxT<JgH2|$1qIUUxtyxol6lbB z@+Vln5v*J&tfe8J%N0vHeP`xj-Nh5}&d_Jg`!|S1QnN@Ci&a%El?{n)noX>UfRE$& zSy&MSDF7*1R><$?^J*E&rLBr_%XS^%;`MqgXclXlMUhx+RjbvC5!ul?)~H8Yuxhbb zEkWfnGVy48hc@|gu%#mXatCCbFywBqAxIKQNmeuqm0E03i*lu6bQyolvg{M)DW<3E zG`wPq%cPn3+4J4qJzU%0fAJC@93H(o#>acL+6g{6I5>Tc4doBgcOSnwJ9~SM-(6h1 z|A0S!`uyc9{&xO-zlMMOJUluzB3ffiAkFe$9ch*S>MpJF|I(7_Iy;r$L}JbIn@VhR z$7Es@G5cI-#kS2oefq~wwp=~2>+`>z-(ue+J2o$;LI3~&C3HntbYx+4WjbSWWnpw> z05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppn qF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTX@`Go)g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_group.svg b/web/pgadmin/misc/static/explain/img/ex_group.svg new file mode 100644 index 0000000..9fccb4e --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_group.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash.png b/web/pgadmin/misc/static/explain/img/ex_hash.png new file mode 100644 index 0000000000000000000000000000000000000000..9f35c76538c3a41920a7b93b94bdf97443df7aa7 GIT binary patch literal 1169 zcmV;C1aA9@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001n zsbo@(8Fi+|Hi*HY#9nXB?oYw#V#exs&h4h&@<F}n38~^Nv*by<=84npY=q5bYthWj z@xa0E#>el?&hp;g_M^vPyuIzKtmw0}>eSTprp#qVzv+I_?y1pfi`DRv*YI-8?0nAc zpxg0|)b5kj@2}wVOTX!?)@^0T>qEQdP`>AE$LX%xagvqMa+aa8;C8`}HuUky@a(s= z<azV%$M5K~?&h-b>%{Eiu<YTk?BK2N=fUgdp10_I@9DMZ-I(RolH}8n>fNlm?Sban zmF(iL<I#@k+^W3rgyPSQ>Ds94;H~fF!0zF_pG#z^7Z=B>b%2f~b#^4RQ$FKkW936b z-9bUQ>wu4ZIPc`Y=+~#`)}`#;yM|jA(>_1o$cW#@hUV0yu-$XX5E0BgJmJiW-o%9F z(xSc&4#hh=;K_*H!-U<zg67eo%w1jR)~4*;x#rQL<<Oz)+qdxO!sgSY<j$b#*|yug zf7-fz<IJAizk%e<p5x1&-i$@K00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0!T?jK~zY`?UU<U5<wWn@pV8EQt5^jN;fSkZ!Z^txZea>#3ciXMG^ue5lb*` zBLBL(BnC@M_{lzaKFl*S`~03W=gh1~bf??Z7>o&i8z-E`2MDn+LnITE(kU`Ph=my< zli!=3;UOHsGB<N!4<_g`tKc-t-v&Vskw|g>!NW(76$6NJ2r~EN>D;qx<f=ddDj?lC zzfvATB(nK=DOmtDJSQ(+N?*MuQ;UmBZ^#ftCYQ_Kk_phjJ0f{M{b7O3OfD}k^&$OP zSQlBxWkuL!wbR&Yce&O%`5J+BAl-Rq6m~(aPN&nN7W801!-mmlLX-KU#frjNP-nB* zbf^P6IMC>HI?ZTyx!j(ABM$Jw28;N7n`m*n{ee-CEij_l=W|)m<M#(C9G=C&reF~^ z#ik`>#q9t^g?o`5n$u2q89~HPuuHQD{TVq$evdr}9gW5IqV%<k!Qp^7d|{C&ZS{Bp z2@Eq#a=+Jwj-`OFxEFRI^_BMcgKP@sAf3+iBOq2Pl`555t<kJ}Ti5ID_PBQove_IR z2<Gz)Cew$9g+65OuP&+V_amCh=Zi_q93GcW`jBWYcl6^=7L(b`W$A2&nV)Qm)AC8> zY=p)*2{p#QmtU5UXB!g~#e{J`Q!Sk0S*=#954-)4+s{4^DqlQEV)eLGs$i|rXr2#4 zu8J*k#g<F0Rt+y2&1QQT(pzk$)oRr6yvav+SrQb(rKlFlofH>!thd|kzAU`IGSb`9 zXpM~`UY7p|xp@{|V|TiBT>>)4pzcQhBc}iW03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfr*~9W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash.svg b/web/pgadmin/misc/static/explain/img/ex_hash.svg new file mode 100644 index 0000000..0d248e2 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABl5JREFU +aIHtmHtsFNcVxn87OzO77BrHpdiBAm1qqkahBjfIIiJx5L+IkmLkylVJX6KPuCYpilS1CqitqjSJ +QiKlJEGJEUkICVVagVGRKNBG0IpYqqCtbBe7Ttq0hK7tUrIxwg42yz7vyR/z2DU76+c6UZL9/tmd +b8/ec7+553z3zkAJJZRQQgkfB2w/0CLNOxbL9gMtUsxxfV7kA785LR0DyTy+4dMmT3xjred/poLt +B1qk83/HaLplHYf/eoK6pev56d17ZjxeLnQvsmMgydp1K4mMpfik4aMy6Ke2wuDp9r/POFGuCMAW +c4ztB1qkGGI8hQD0jqT4y8UEy0May+ZpLDBmlytXhANHTDFQUMiqCoNyHXdFloULhk4JdUvXu5N2 +SsvhD7FnVmNDASFr0mVc3TvI9fb1MPAasGZxGX+bYSKnfJp3LHab/NCPL/iKIQIKCEle0Gn93g2M +jWUwTR+BgJ9PVOg8vuM/RUmq+f1FGScXBetlZCTN8HCKYFBj3jxFwJxaj0zkeBb/NfyGlXbN4x2S +5QvF5/Nezjm7wveA43i9IykMzeJuvk7n5PE+7rxrJX1/xBXy1Q21HDzSwzebaum/ksbQfBjA5+br +7PrtGX648WbejqUBMHw+loZ1Htvf7Zm36EIg63gODPuzZySFn6yQf4+mADgXU/QNJzF9ENB8aH7r +hg9eSfPmaJqQb/K9s6CQigodXfe5PRIKTb2uV1UY7ndDg5rrdE4CtRUGfYCmW2k/P9+gB6gOafjF +dFek2s61LKzjuL6zItMSUrMCnt8b8eQnQ315hD+fGM+dtPlX/wBLDdBNS+jBIz3Ul0f49eHx8cft ++Kfbvcf3ck5PIX1vMGPXakq08fB9z5BOXcomMRbQtdfiN+0BTbfu+J9aTbr3tfFQ607SyYuIskrI +byzgzCttPHjPk6TiF0EpEEEPLKRnfxtPTlUIzNy1ANKpS6SSFzx5AL9dWs51Kj5E8ur/s5PKKJu/ +SOLyAACiFGamcK/MSbMXgtgTdJodUeN+V5mMzdsTzmQQpexQhVwTn4v3VYgDZ0N0SklllCtCUhkw +lc1LjhCxSqwA5sS1dGOB+10yCr9WkceD1QsARnChtQpKISbogYUuL6JcAUagcnpC1kae4a0vHcnn +6zbw/CQizCUNdO29370+KcP0yhjLo2HevunLsFVzf3u15iuU1d/IGX7kOU5v+1ZPHg/f8hQS6jzC +rY2NaJEIAHGlMKurOXU0X9y1SJ7vYPW3d7qNvPOVFjZv2sxzv3qOT33/s0C/G3trYyOnjh7ltmfb +ScaGABBRmMFKeg9uY2XzYyRj77i8Eazi9cM/88xbsLS0SIR9i/roXO3cwX/BCo1mFk+4ze5Ug/BS +cx5/73fuZffLu1keDbPrxTbquhUjg2ct8bEhEmMDbs84pZSMvUP83f5sn5TP0LU6V2s03bJu3GnV +cZxrPzVdR/NraH6/u084NuvgB/dsYdeLbWx7JA5AosZucFGIEsRpeNtmLV65QmbU7HGlqOtWHOZE +oZApY/OmzQDuSgBcURkCkl2BrIiszYoS23ZxN8VpCzGrq7njzRR39ENChEB1NW8dP87d0eiEO2PH +U2vki9+yd2Sgtf0+AHa/vJvbhz/D7f061EDAHpOzZzEClUhYQARBMIJV1hzmVUJGAYIIGKGqgnk9 +J/XS+hYJdeY3dqxuA989NvGLgtPtD0jyfId7netadftG8+LL6m+krD6ex5tLGsgdJ5dfu/GJqT2P +nL7hflof3lHgrDXxo2nyfAe1X/8l6fgQAtyUEYzgQnrbt7Kq6wWSsShg9YEZquIfh37CF5oetXgB +RGGGr+f13/2cFY0PkRiNZkWEq/jn73/hmXdOzlqp+BCJ0cGs24jjQlHilweso4rk8FeiXB2JuM3s +uFdiNMrV4f/awnOafjpCZgOxjxbX2qlkxJpQZvyEUdbu7Vy7vNP0djwTGP/cCJnITjP5dioiOSJU +zjg5IibBnJy1zGClbanW5EzbbYxgFTJfrDstYIatF05muGrcKphhKz4wf9G4VQiUL5qekNk8IZpL +Gug9uM2T9zpemEsaeOPog568V2MXOmt5onVLj3R2vSuvdVySU6eHpav7spw7F5PWLT1FfYNeTMyJ +a30Q0CYP+XDgIyNkTlzrg0DRXauEEkoooYSPFd4DN2wn2zUthj8AAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a4e9369fa78c6fa19bf5c7814f8a586aed5565 GIT binary patch literal 1571 zcmV+;2Hg3HP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70008nP)t-s0001) zym(TL8Hu^uHi*HY#9nXB?oGhyVaDrr&FrS$@<6=l6071Yv*bv;=84npbc@wyYthWj z@xa0E#>el?&hp;g_M^vPyuIwJtmw0}>b$+})YS8(%Vb!b%R{~CN5APyzv+9??}XFv zsL*Ja+3}#;@rKgwjMVOs)$Xp~^8}~i38~@_s^U<>>RiR^tJQ3E&Fq2D?Owy^WyR=g z$LN&S@2=W$rKse3o~g3nc4CU7!H+id@yYP)xAgGH^YF;E<$Ck&#`5gN?dGxV<go1H zu<`1{>*k;9<(}{Bw(se+xaofG=CkePvFF;B=Gm3z*p%$yuJG)(>g1j3<DKv7weRV) zy6u7G*OTSelI!2C>f@a0;+*d1v%K(x<kgYn(~#=jtG|XZw}gPOUOuu)6SQGJ#E^t= zX1Me3$M5K~^6ka(>BI2n!Rp<r=g_IQU>nIz8rM-G;Z!G=R8sZm;ipq<sTUX9y@`O1 zC4YD<y<0}QY$D=RDF6Te+NO%`W@hL_MC3w4-$6p*Vq@;+vbpPkl6^Vv<iF|Ls_ELP z>Dj2iYBa-eL+3+8i(D9Kc^QRT7SldI;mwQT%ZlL2iL*-)v`iG?LPDa(U!=)mr_E-n z(rT^OZ?N5Sv*LKR=X|^GgU%8X#}E+AJUr>yr{Kwm-^ho)XD{18K!jQr#Saj^4i3gU zJLuP@-^YgD#f8m}Tijt`&pkcLJUqoaJIq~O@aV$q;H~T6t&4j%?cclR)THLqq~_A2 z<;tVAk8q1xa-mN-ut*Z8oXPO!!0Ozp?&H4g;k@V8rRUY8?B2TU-MQw`qUF({<<Ft( z+PC7*jpELX;mnKa*r(^#rr*bh-o}RB#D(V3q1?cM+`oX^zJTP;pXb!1-ou35!h_tt zfZM%)+q{0{&7S7dqus-U-NJ(0z=GPledEiX=hda<(4pnepzGPT<IJAw*tWHqeqb;p zI{*Lx0d!JMQvg8b*k%9#00Cl4M?`-}zj5UN000SaNLh0L002k;002k;M#*bF0007X zNkl<ZNXKJf7zG0g7?~Jx$}zKm05gUTR@{16*w{HZxmYlCu;SLk!p+0W$B(83qywmj zG+TfU!)c3vAP5Mc3p3%ggMmR%NLWNvOb|nhI36t$l2Xz#a4paPWMPtJVu7&bFoG0K z3k#dPf}#?OGLs6EDvO%BhNc##XVJBAYwPIhvFI}yFd4EK8Jn1zVFoFhU*NWw<F>^D z9AXwQt|i#zmMlzGOe_$#HAax4*<xdBXJ=<`<G|#|<YeRQ;_BvZgAt@?ezCFh@bvVu z@n-U2^0o2v4+sphK~;c7OR#51XqZhnQv{Qrjay)3R5W2NULi5D;Wlwh@l0+uK~V{b zNy#axY3Ui6c>I#(9iE+I;|$c2Ym*n9lwVL-R9sSAR9c46QeFW9<uGogjg3teQ*{MU zOGOQkZBtuRS65$OSJZ&eQqkDd+|pVBx5X*0jj5ff1E{67qO+^Jr?<Ecq^GzKNlX6( zCUnpq!8DO+(&UQnDO0CSFR2IVDVc$!WhN8rEb-a0b5!OU%rl>FwZL(qPkY27ro~H^ zRxF#ge8tM*dXOFzTUM>cX3Od|Yu8n*U$J51rXrA6Q2nxb%hqk%5q{aRa~IGryTO8c z_U_w%fankd0dR=f96WUR$l*gr@x;rqq~l#DY)-B}b^46W*>mSFTqK;vj$gWb<*LoK z>o;!hx4Cuu&fR;26AUO|*W29R_~79!n+uN~KY2=63n*ak+dO;z;^hUKdyk*IdW}U3 znqN*{d$Skli(7BsU9@@s;lt~Xn0`Uam6hO7LMA_<Dqz4_j^P7>7)~85T1fYc1xA33 zf&m5qP2%gmFInOH0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZ zFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-W VFfhuORjdF2002ovPDHLkV1kgxQ(pi8 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.svg b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.svg new file mode 100644 index 0000000..256f039 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.svg @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..0051f996783873a4a27db4b971135e95cac8d744 GIT binary patch literal 1452 zcmY+CSx}P)6on&<ilC9wDWY}j1EW==VG&s^MyMc>VE_dIWsf2%OOQ>VP^3a>#ezbi zQ$WfpN-;oW2^b&=k^l*WB?JiB_w`TyKVY?Ov`?Km=bn3K?)P@ef&wq>vfO70gTZ$B z`}qW$(($7$%uVxaUUo4IW>yn~4)ryiwS?^8pZAsxthkhpJ|kUEnO0vS%3>*s%xPsS z2k<7yY&!WTdW3!iaT!ycQNDmlo}HT35l7XO3C;8jz~MlDOvDm~m7Oo7J-u?muxfr@ zpW4Z+8|Svr5=g76*J7xhadTK|9F-Zn1z?W=#EU?ha)Ykg7?VO|88jh>7B!m<YlhB+ z+ihIKOFme=tgB-K^{c?37$i!dE}kC8*Y^qZlX7DhJFTT%m|NeG{<NMuQHSGZ&NB!^ z;v%k3I!Km}R=5~+lUn8L%?)9nD0kB+*n|W|{W4?{z}f(LBJsvL7vc+yV)2Gr{Z1in zFoNuUS%J~8tXEIz)ik||2I-d8IN-v9etFrj#(`wAO|24dG_VI%MS2w#P*Oqdl0sB3 z7yho1^%ArX0Ocg0m;^P88U<b>@6$+o03~@7;%^vuMm@JJ<aWoNJuAayg^%p>Gmnsy zuG1*Xb4;BYgOU392vO(P&!Kp6@p=_SEyk&Y-2;lk%6vCay<jj&HE-0dOV0b0N7*Ii z>@A6~WuE;;C#7g56s?$SP%?QaR1+n-c`~kT8uNVa*2|@o?lo)=KN~N}8`2cd*w{>1 zTTgj<YDFZyg1O@D{UE}YyxV#N4ySl{7?kr`5m_T5X@ui?`P^!3EZxhC>gh@L@R+)G zO(PhQvf3nzE#>#mKw1u{SyOTb#j{N!#xvnegJKyEY1bgl8X%hmqzq8Kx;j$0LMUJl z<qK%_8X-v|7+3Q~)m)Q^fP}#wDqs)hYxrZTbs`|9t4#~%jZRFLv+$sL4Uo=)sui7h z#-L;~yHiyh($Tl5Qd2dzWCRC>z`VsQjOo~s>UR}uO21G3b~5>_sl;f1pL3yp6Y(*2 zTg|QPYVFdf4n2i1ryt-~R&&EyEH~GIaAZa|e{p<ldYm><(Ym$Sy#1kbWFdS!sl4#8 zg+-&46R)?p=v<IrxKAkB`h2<TL4-|Z@SI~R;xX*W)A-68l_8JKw;U~tw3<);5q%L& zO+WVhmV94&T?E^GFg?51+bpQUzhTmQhVhm~3Z0o+9h<ZCwR#@S#fJ;<<Zb)oT##J| z)~QSg4M#(dpu=3@PP3E!chc@*v$C?VU<{A|;Ea$C)Mvphc3Q&ID5^bSMg}7&YYEw! z+G=rs{cXF{PQvQnc;JJIsEn$r4gNJx`JpL<IafAY`AhBA`O0bGjYCz{Rlhy-wHk~D ztSrl;%8Mf2s{-cqz(t1-!B^mBiO9Ppot??{A(!2P0&-5fl5P>dx>DZULg*TK_Nrt5 z-2iOB@sKY=Jc0s3a*{6G2s_h?5P1!wrHzP^j*5=&P&pEke^pz|yOz9TpDUboGQjBx zMo!1otB@1eyV;Rc&(=*V+v==K^@N)awupf0xSm8APIR0a))g^~LD(V`iz%%B9lV<9 zNW9qx+^!S-`8sx=M=9LFn)pSWRENVZslD!B8wv}&N}w0~Q)Iq<_h*6eL%R>T<xbtB zHVKX_vJbiD$PIhPc3|ksSjnS-lh?8Q_gnrdZaWp#?-x#cg*}W&rboNyF#et@q1F6p z9T*>0alj*U0b~~`wx_Vx`_n~Y1o};*=weXmz#wPa!-WHU)K7MW;+k{KB^hrTOISzk zQem*}7uv?l*3EgQg4t*IhG!(iW+b}Drze^M=7@AaA{-nMNQY2Iq`R||yR-9g<Y{*# t(zVw9;QxR-DG5oKoc{o%+b7`Tw>#41KY&_u`GpC9`TGX?bfIFt{})E(L^%Ke literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.svg b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.svg new file mode 100644 index 0000000..730c6bd --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +0gAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png new file mode 100644 index 0000000000000000000000000000000000000000..76c546a4dadd7fdae310dafcec2ecdef9649d4c5 GIT binary patch literal 1377 zcmV-n1)lneP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006>P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZJydFPPaY zjqWG6vC4&kzm|uj!nL^a^ZV4*@~N!lj*;EL!|c+nY?{_9i1sFWzH5(?-O$nT?A*cg z?Z)orvhC!s?BcKR=fQ#6N$usa=Gm3y)|2GZkm}s3cd&fiz>e(VuH@B`<I<1f&W!2U zr|sXy;?RxZ&5Pj5iRaa&`u6Vc<G$$Fr{~tC?A^KS-n!+`q2$h=>)E#4zJS}je%iZz z<IA4fyMEfbeQRKz9{>OV0d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U00K`* zL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U6fJ!G0)j%qd?aZR z5fu}c7>rs-_lqPS2uKb<h(XgGuGEK33lp=Hw2Um1oV<df5)(cx$|@?VY7i|P>Kd9_ zOxilSdivP3!2P0PU|<N*L%<e9h$*WW0rh~yjKRJz!Ik=uLrmGoKm|mbnweWzTAAVs zOBC;`SVOd!+t}LKo8n3rs9GE#S{$96U0jLO;s(*;?&0a>jav({i+z0kltEhjT>}Dx zaQX!$jRpIKgaY-1nSww#aj8!^Gy>=})5xgkm{?PyQeSXrL>$l-)A)qMq-30aK}mc* zDRE%Gq^6~3Wa89<QYfipK|(A$CpRx2w-)50Po)5&rLZW!xCEzPP;Ds%YatL~kR)gf z39qtp6+&Uk08WDD=4PfK4Ju{j6{^H&F|VwwG&cpi3aCSkSS=P1TU3bB0n$=sQ*DYQ zQd3)3UtibI*wozI)Y6L8FP3fY?MPZWI=i}idV2f%Crq3;Y4Vh*m|7qK8ivp@ZTgHE zGiJ`3J!e`6kUM)8rXJI|^X4yD2)CuC6QpC&l-Udnb2@84dZu8w&2;gSrOTGXwbXV2 zb<9{X8N^;$3nC}CU}#yjdd=E(a4mJ+AT3RkK<xE(AaYU@hL*q$8#ir+YpL%6X=$Da zVsEJjkrSISv~1nBJ$na9TF^p_D2MG#-nDxVY2M$pci;X4qy_TsgNF_wv=9}Q2M(cV zAtJ$;mK->6poFAkiJr!&3jm~}-@X0I9(w=)03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfh#BXQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.svg b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.svg new file mode 100644 index 0000000..acf1548 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +SUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png new file mode 100644 index 0000000000000000000000000000000000000000..ba24ed16aeb0d93bd133902b0b2218e674f84528 GIT binary patch literal 1402 zcmV-=1%>*FP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006^P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YN)&~ znAt0h?kBgg%7uZymWQOmwYc*0`_$F)sjTIWk=?<=?9#1ln$|0b_9lA1YmbuM(9!Yi z+`;qh#_r~_?c}iR;;-=M!GYRI?d7rN*_GwiljPHo>fEY#uzcLWj_l&D<kgYm(vRZK zjOo~??cc`Y(2e2Ei{Q$M=hdb9_U`ZFzUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyHkc~n00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~ z0%b`=K~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4 zBxw;56%&^jj9OrRk(88VkYoTMLO_ZS1f)P}iPb`eEpWepZ2==#y2F+Fuz8<}Sz1O` zj!9lYQAwEzpB5EWRW)^p77h(fEo~+pT|IpRY+B&4uWD#$1kppl7I=sOZ7~Mw0g0J_ zePN0#^&zJ*6=OqH5N&2|VQFP;hAZ`<cwf~9qQ%12&fdWcSGqve;t0{=<m}?=Mx+*Z zh!zh|FK-{*T994r>*ucm(h}en7!-`tFNhEWf)M}EFrc1rGZ2VCmcb2F!XklAGmDCj ziH$QOD!+z=MaBbdF-u5HN>0J)7nH>3n;H-HOImtHW)@B@D20-0HYCJya`W;FaBD#> z`cw-cT8fGbN=kA11=W@^uoeO#21$Y@knk$6P$d+m4B#YaVPS3t(x6&iQK?3Z7K^H? zDho5PtAIMxiPd5Wu|<_A9Uv{$wl!u*BDHn(4Gr~;P0cMW&8=-%{bJSb(Sf9;v#YzO zx3{l<!o*3FCQq3<4O0swK*JF_rq7r;bLOnsbLLL(1ajxh#?)grZ~lUXi{Q4@c7b#( zo;rttVQyC~NY7LZx0x+jx@`FhxR$zZppKa<r-0b2>Oka_Rtznx*Q{N)9<HUn2c)HW zGKjsQ9z;%V#?TV9ant54a4ikJAT2GEK<upzAaYU*hL&yHcjW9ONefzt5#_L5DZBUV zCC&T0_w7G$khDPFbLjA4gchQr^59_<Ekq<3v(keH50;XYEYZ^#bpZet8{@o}32r3- z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f<D*lWB>pF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.svg b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.svg new file mode 100644 index 0000000..b1a51b1 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png new file mode 100644 index 0000000000000000000000000000000000000000..fb536b11b68fca6c2feda14a8011003678204d62 GIT binary patch literal 1389 zcmV-z1(N!SP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006~P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZLlAj_u#Z z`u6U(vC4OVr-z4&!nL^a^ZV4*@~N!lj*;EL!|c+nZ0y{@kCNSe%Uhb(E6~yL^X<m& z=CbYNu<YWm@aMsZ_9pG+vF6#8<<^tr(~#=is&%M_sJt)i;;!V?k>k>j;?9ie*r$Ha zR+!l<;?RxZ&5Pj5iRaa&h3hnp?kDf#zUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyg@M18hosTq4gLTC00DGTPE!Ct=GbNc000SaNLh0L002k;002k; zM#*bF0006~Nkl<ZNXKJfAR90;fdC^ZT9}wwSlQT_NYcW=$;Hh>nikS+;RXAJmlQ30 z`~reP!h9rY5fK#=ml%v%NcW2*9|%YeK!`!p9j?@eO$!sVl(dX2lbpPQq7oB6Ey^k? zs%j7|9O@dHT1?tHx_bK9w7~tMVqjnh(L=x%M2IP?7y<Qw#EikdFu|4jkV8z_$Up@| zo0^$hSX!Cl3QH94t5`#{nA_Oe*_+}@7pPhsAX*%qoLyXr)Zzxw;_l(;<&9elvWtCu z{ggpk{9OYAgK+u<C5;99g@gk2gqeasIB}^@IWz+3G}Fka=$KejqEcUQXha;)7Ss5I z#H3`LenClmJ}Gfvzoe$6XJq2kf>J1{WI;kKJ0~|UAGa3dqEDp&qNT7XzqkaaUr=o+ z1#2M?Vvr<g3<<BYauq^h$^cG+=H_OmAPp*I<rS*LXfdy>tTZ<Ty9%g7jaV%f5L;A; z(gD&^Wm9d6BvMmbS6^S((Ad=6+|<&F)i0K9?(IlgIy$?$dwP2N`X@}BIBD{fshC<I z0UCzTF>N}KoH}FXtZ5xU#_SoGdQ9icoi~30+?JY7kdD?VGZ!wL)ma15GX=wKri&IY zS-K3arM3%1wk%%=1S@Jm?8z+{T2`)Fy=E<3OI<gJY+47>vc3+)p45b)C2+&WO`G9b z>U%(B^A?bnt@R-G#AXaF+qUn>-bs=cv=Af8VY`xd@7YV5_jm8xf8Zc#fxPF?;ll_m zL`CJn!zfx{3FgRAoC(IX<lw=BB_t(F^fX3Y007N*+;lfqX*B=<03~!qSaf7zbY(hY za%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0 vW_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfuI2JN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.svg b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.svg new file mode 100644 index 0000000..4cccc6f --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +TkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0018157f64a5ae601a2db08fb1e4a553385c33b9 GIT binary patch literal 1417 zcmV;41$O$0P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700072P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YTUq% z?cc`w_U^Z_%6EXLhlh*8wYc*0`_$F)sjTIWk=?<=?9#1l?A*bRlHGmFTbkA@(9!Yp z?Z)orvhC!s?BcKR=fQ~fChg_1=Gm3y)|2GZkm}s3b*P4@yf5tHuH@B`<I<1f&W!2U zr+&{?nAt1h(2e2Ei{Q$M=hdZ!>okq-C-39F=-8*{)}`#-x$NG$<<Ozz&Y$bqw%ope z+q{0-yM5!!p4z*9+PZy(fxniAqyuE0`2YX_0d!JMQvg8b*k%9#010qNS#tmY07w7; z07w8v$!k6U00L`CL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U z6fJ!G0)j%qd?aZR5fu}c7>rtAevy=vWRPS4Awock4+Nw@YKhfChAnWvfNcRISh~ZN z`mlMQiCJ1kR*p$tK~YJW37-}fRaG^0h!zeFO)YIE9bG+r18iF0v9D@qXavziz!rFj z0c|k`>H&$FfPG<#EA=6#F%@G&RS<1vZeeL<ZH6oLp?F`_2BO8n*3RC+3|G29)#3=z z;^ge&>PDm%cZe1bPcLsD+**)b?Ca;R0@4!T78n$a(=Uh+1A-9$&@iB$a5E5yK$gJ` zRKg;GPBV*&j){#kBPzd!ghj>!Z81woOiE6{=@*p5=bIW2_DfoNMrIaHEhvSOYBnUq za&q(X3vg>eF8WjpAzF%x3rb3H`UTaNGO!i`AqGi;CXnzduTUivrVQXDXklS)2GXEf zUQww=j24TkswxXJu&aPN)QQz%39&_$C><az)wVTeNFud$^$iX6jZMuhEzPZMSp8zv z?$LpyrL(KMr?<DSf5OB`lO|7@It^0`BtXLvI;PJ6lGA3+nmxS}$e1$|Q;*r)dGi-6 zgxgZv1=7(rb=IOqv%6|RdZuEy&1~_KrOTGXwbXTk$kr8$fM8`Eh&`nhL(8hwYu2uV zYpL%6k<IHtS~k>!*pr(vv;=M3w0R3$OG7V+Y}pFZvaJEcp45V&W&4huIlD;Gf)-*# zIc#^zp1u39dcPZ&_xJ2SaPSamfxP$dks}B#L`CJHBPd#63FhcAoC(IP^w6P0r6eUw z^fX3Y000U{;7!~3Lt6j<03~!qSaf7zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4Fh zG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bN XH99ab%9mBF00000NkvXXu0mjfCZzUl literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.svg b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.svg new file mode 100644 index 0000000..33b4dd9 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..3a78fa6a1d35d8b2666ee3ffa5583db9662a67e4 GIT binary patch literal 1490 zcmV;@1ugoCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70007fP)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j_U_>5)wA5djnuJo)yKTSzu&2=<&>D;#mDaG==ksIwesx6?A^lL!H?z8tMcd6 z`}p$9v%Rr~oVtpQ(zUVm_Wa-A^}oUFs;%YG((&EGk@4lw_t?(XP%76v4Bcit{POSI z-Sn%j=JV~w?&h-X<go1Gukh!=<GQ)mQY+$cP1;Eu-)lwf<+0}3mF3ox<kOJq+^Wd6 z(8ivy+*T~?;;!V?k>k>j;?9ie*r(rPJ=a7P;?RxZ&5Pj5iRaa&@3EfMdPDEyzUbJe z=hmg{-MRG3zUrWd?4*wR<=^byy5-QJ<j$Y#*|yxifZM!&+Pi(@%bwc1e%iWy%Ued< zo^8}&Lerv`vZEDM00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~0*y&T zK~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4Bxw;5 z6%&^jj9N(dizFWiNDe@VLDL<s)Q3$A6SI`Gj4YF!yn><<6Fx1<Dk`dK5G@?)8k$;6 z+B&*=`q;F<{i0%EU<lDez!pS^DXSO(^?<~T!M-rTmHLoFOxegl1w@;gnOj&|nc@md z6z{88L$sLN*xK2f;z}2&S{xu+9G#q9T#3};2GQc~;pyd#TMM#_eSH0tL0bG>0|J9^ z`UNG81^b1B0`-KMf<QQNsZTjH0_Zf;$f)R;SW}`>UvOwd9MBfi_=LoyWSo9MNqjyj zabUlsrln_O;?#mtD5+#YLM%HcH!mNz7UZH&r2wL(uqeN{1gBq6Z7Bt7ArNAaBxno? zud;F#LSf1PPJ-s<W~LwwDrMyrs>En9udJ*zHwC*2s6&ldEfx@4REW|6(o$tpZHgpP zQ(ISGU)Rvs)ZE<E(u&nDmTm6sNLo5NySjUNdi(k(Oq@7r@|3BVS|9-$hR`u>Is?Ou znX`ak_8bO=x$`jfn9g6YaM5D8Ej67$9SlomEnT*J)~ppk=G-Y5ZZloEYW146a4of6 zAadP$28KBsX3YYzC%0f|*|=%*maT9tb=@GcX%djwHfuYGJ*f#pOW=;3yLQ91)c1hM z=7|gpduGkr3t~@f#?Z2F|AFj-7+MZ(n>FijJ$5Z<AqI2Uky*2jcGux>*s<i}Cr+Yy zzhyE|3qw~e4(}g7b^6R%v_Nj1GM9m2dS?xeKt6Hq{CR{HNK`URy)bLm#SR7>QF-<} ziWX>sxio9mWn2lywB+pBvn3=YOY}5GT>t<le%ij3CAg3P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f^-`z-2eap literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.svg b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.svg new file mode 100644 index 0000000..4c9332a --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7764b74f5e5e5af1a205b2ecee9ed184727e1fe0 GIT binary patch literal 498 zcmV<O0S*3%P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70001NP)t-s|NsAV zbaXa|!Dg1x!H+h2o~cd1>4~}9VaDrk&F*&1?7h9crNQLey@{>X>89TD^V}-D-R=M0 zDZt<E!r<=3;qS-e@W|uv%H#0M<nj6DU(Mz6|K?xO=kn9&^VI3|*6H>3>xcgAhT-q` z!N@d;00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0Ut?3K~zY`?bO>2 zf-npQ;7O;V0?Nb_&J(=<J35L^UDqjzCdSySWyu#<`)@-0>*s42VGTQwXf%l9@iclL zNdOXeuiySypCM4!;O@y&X{wSOIUXq~XQs-}6QvYS4hKrA@L4=0l~^f9_IpA^Zz9B` z$BhkkJMf8s@sL*VhLWpb4Q#i-2+rIQ+9-eP?noQ0lYBNH*ld8!i7ZVDly=E_-I=Ub z0iwNRxdislWu;A#vn&>!J9Z<@Ox#J(okv2`=*=e-1+Z!K=krEr8ku~;d=B=YX>j2X z3`^5Z>~y=h^w%!z!<XmH<A-BxricT_g}zMDF0MB}&$8Uyetc9c(E*Y`k!1ybMZHLj oF&RsOM{v$!pYbjo``5SC8S!5pi4Z+;&j0`b07*qoM6N<$g5#I=_5c6? literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_only_scan.svg b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.svg new file mode 100644 index 0000000..6e10d79 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.svg @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAA2lJREFU +aIHtWE1IG0EYfWuaFYqXYi0l6c+hoSlIQ3sopYdGWFolB6ElIFTaSwtKL8VDNhd7LYJSEA9KL14U +C4WFQqCFtik14sFaEAOiFi0GMdiDivSHmqSZHuLqJjub7DpjuoY8WAiz37yZl29n5s0nEEJQCaj5 +3xPghaoQu6EqxG6oCrEbKkbIsXIM0vtuiSgzSeq74FUXws0egXWMsghRZpK4cfsyvv1I46SY+wga +agVcOSGi/9UMws0e5jEq+9Mai62R8bkNAEBTYz3a/W6m1N86tY4P73O/v2vaP+2+4wGqkPG5DXTf +uwgAePbyK9r9bqZBWraf4+mju3CkF/LanaIXEyOvAbQx8QNF1sivVJaZXAtHegGp39NcObWo7DVy +mKir2b//pDjyGgrJgu+Fyyl6AeRPPtc2z4W/LBlx+YKYGFEob+bh8gW5jGG4Rggh4HUN9khhIbLm +R8bXA3/XlODvmhIyvh5E1vzwSGHmUx0oIiRLCLKchMiyTAKBACRJ2pu0JElCIBCALMtcBjn0XYsm +QgVPMYcqpJgIFbzEGArJZHPPQWFGhAoeYph3raWPvSQZ1+9IrW7AhQYAkimec/iCVncMsf7rOjEu +X7DkpsAsJBlXcO2+3kf9dV7C9KgCjxQ2zXPzwR2kU4t57Tk/VprH+EC0sGPRfJR43HT3PaRTixD/ +fLbeEUWEHLVSahGLUn6IDH2NM2KBRPVR+jZrPoqIXhSuaGKSxzgjWXNSePkoZh7VU2mfjsFZMpnY +IpOJLdIxOEtoMYVPKBQi0WiURKNREgqFTPXhycPF/VIOPyLLMunr67NkCJl4jDISW9kksZXNkhlR +/8HCdqv/KCsPkxCjwa1OggePQDsvOofipD1wFgAw9nYVLx779lJrZEm0NqKcMSosrxGaJSm0ETS7 +YRQjaGLIAWKoQrSFuYxm++0cihNtoc5MaafQbtAKDUJqEdDE0Fa0mRidkPG5DTwJXsD6zx1s72QA +AG0tZ3C6rhYDyrKuUKdWRMxUQ1hObTPIu480NdZjQFmG6NjXLToEDCjLaGqsz+uoLevYAXkZ2f10 +yOibVTxsPQ8AGI4kdPVfp+gtWdYptC00q1FoSQ4aoxOiFTMcSQDQF7HpViLfRpQzRgV1+z2KqJja +b1WI3VAVYjdUhdgN/wCBUjPUN8Zm6wAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_index_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..d44eff429fa9a3409776ea88a11421582f6f4598 GIT binary patch literal 1298 zcmV+t1?~EYP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001q zx!X2~!Eep(M7`;C&hL59?^VL-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUOPl=ya2odY-AJ!Q^I^(ZP>4@#=@|<6!gf$nfm8 z@9DMj?Zxiqv+?W1?BlTT>B8af_vhLx>g1j3<DBW>n(yed=-!#<+?Va;vF6#7<<^tz z;H}o__3YxW=GvC*;jZM>lI!2C?dG!U-mLKEz|`sV%c5A@y@~4Gs_*2!)9CZ$)RE)T zkK)jc>DsB$=kny!kmAma@8e(T+p6Kris{*?_Uni3;k?b|^7G_h=+~#{*QV{@yYAa6 z^V}-n$%)^{h~LMD=G3Ii<nj6DU*5)s%H#0o)urasqsZg%{_KYD<-qLSy2s=2#o_P& z=3ngIy5`cN=Fy_&(V^_zxc}ZM-o%96!-L$xg5}Vm+`fRq;O^wkpX=JUz~AoV&7SJn zw!Gc#+Pi+^%$}{*>Ep|u5BdaA00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0?A24K~zY`?UdPD5>Xh3ZKAN;Q_C#*KwubLStTT}1_fLIkws7h8A(MzWmN>> zU-!(C!g1n>o1QNGE)F-m&yV-_9Zp~0%lzwkMX>Y7Qw$+qOC*vv#9OIU+E4Vqdp|Hp z3=Rzsj}RlHV`Co(QA9F6K0ZNAOioUIBtA_|O$`u3pQX}aVsv_XV2tRNGV%8*U%21Q zpI@J!9p9ai$!5?8$Q25O9A=eD<t)sqR4O&7Ns`onhN37fbRe?1IT?#6=I7@Xpj=p3 zRDo(~X=xcqonCJM%4js1F=S<>16kw|9SNjfucyFbG<8Q*i!8FN(;>v5|7N7XYFb^j zi6er`Z;S7og+&Wmv(4_nkhL`y`2p<k=g;S-7$T&omq}6$8iRq-fYxd@JHSEHv=d8N zUvG1Hvaqlg8+M>wZnp<RHaFW4Qm5mKHCn;Ey0JwA?RIZ>L3V^<DXv)CmdizhcYE9C z7f0lZot<3~3#Z5L4`9gNUeAs32*`uMAWESuRxLPecC-tp*W+<QAQTEmL{lKRzaI@^ z7CvMViX9xrG34k-K%&tED%OOq2kmmXz2Ncrd?5%Q942w(_?SncEW#FR7mD@!VzDr! zlF1~4AtxssvYSXG(yRsji?awIi*PCekvPMgV#wK9&yAg*b1CUWCX;4&;YGXf`$GYU zq~h@lIL+qrmmrE{uCA^!xWzRCxk9m6>W1*wBNU4rq#&NWE@UBJES7PkQfWgTi$%L& zt_y`cl#1nYRUAoYSeFiqTrPhDH>GOz219Oddv1(Jgp@!yg?4elFxgYMER{+qrCO`q zwWpwmuU=;#Kf#5+9!!C=D6<x|Mx$}xj>y*P&1N0_`voL*$X<^uSL_qg>P)FLo0X@O zINC)Pazz%YmdlMA+~Wvh&>fq3bh%)%n8jVI)w=6!OnAn7Y3ybGuXzBr6b33x=w6}# z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f@j>KSpWb4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_scan.svg b/web/pgadmin/misc/static/explain/img/ex_index_scan.svg new file mode 100644 index 0000000..03e7e84 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_index_scan.svg @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +5DFOtuJ6IQAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_insert.png b/web/pgadmin/misc/static/explain/img/ex_insert.png new file mode 100644 index 0000000000000000000000000000000000000000..862d837277c99e17d2b66232de79fce010752e7c GIT binary patch literal 1065 zcmV+^1lIeBP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003yP)t-sBmgK| zTU$1W!3nA2a+aZzl9IuXHmaF8ou4@}wdHlD$3eX4%c58k;}QztMoPfx$EtN*#Oh<l z>TAd7XvplT#d&Va>__Y%vc!A9!GLwm?AyJ6+r5e0zJT1nfP2yJ+`)o`(eB;DgM`!Y z-o%97#f9F+hK$ti-^YjF$cT~E?%>IZ;mnGc+417ejN;IZ<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp;FQ>)N;I-kIv%s_fjj>EN2{-mL81y6fMq?B2TU;H~Q8obBJc?BTBM;JfPNo$TVT z?cu!a<FM`JvG3%*?dG!X=CkkR!0_h4@94Ad>9z3a!tm+B@a(qn>%{Wy#q;gP^YF+M z!Lnrl0004WQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkQhe<?1R7l6|m0NSt zP!vXK&`lBB2CJaOTA)a|q(Gri2tkO1TjWv@3IQV^xBmZM;7QKm5)32GIHM2U59@)+ zO7{1iGlRkKH2+{;P|ED2o<i9y7RwoRabmSzQkSo7wrlG8!sWW5Zmt4>Pn51=F&d2) z>IBhBy)v84HtG!NF6!#^)E1!r(pR3TJMW~P0*}+_^l{1Ycsz%>EXy;PNs=@H{0soS zsZ1XpT4Ta-wOSp4TqzX#AZ4@ZCSYUngQhh~OI2D}smLG~3Iz$e+4NHRx>yYJuvW$` z^<kBxN(CwX!so06?Q|;DAWA+@Hy5zZqVB&+@l8$9oxr5os0~RL2mO(muAG;k%==v= z?{&03tR0w-WO+_F>-VJ@Oxn%n5Qd^C4wf(0IAs5IimsC4t_ET>94@Z+-*8Z+6;vrE zDmL4OX6o)%1Th>A6*p>99W@-O6jM@*ZQMqqB9uZQMgW7>p*i#m+5guRgQ6hxVDr$y zp&Tmg*VxiQ7K(#Tq1&Di4jVOe7K2i;IDj6{=Q^OhkHF`j9~j8~+7t{*!3X_54z}(v zzyVU)=`^|+m|`><E<urD7#?zdpLbg!qEcy%5Em;j!C($DUayzcSJ3|AcS0pa52eUu zI?&-*wyvxEL1XK$h+=6#I1mKB2b~PZ-9tT@h=0*v4DY{{!oxzs?R3WU6?`!;`C!nW z0nY1jCn4^1p6^g_rK@7mS+E|rI}S1D`FTWN!TW1cBogs5lw*-d`L~U|Gby8??pJ!b z3_1msrXytzkCh?RRq(}7X*#mo?MOj9Ce&3jKILMl+*jeyDI_uXRqokjvW~fDmd(cA j94hm6lTUy1|Lgn&xg@`Em^A9100000NkvXXu0mjfS$;eB literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_insert.svg b/web/pgadmin/misc/static/explain/img/ex_insert.svg new file mode 100644 index 0000000..2f7764b --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_insert.svg @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +RU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_join.png b/web/pgadmin/misc/static/explain/img/ex_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c391233c449bdc5a0d52d50f522bd3e35c649c36 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_7<@W^2*R&GEgz?Z3h8!ou#;)brTc^v=)n(b4kM)b!xs_i~n@ zTZg#3z3iu{=c=sduCM9E#_!9_@xH(9#m4Z~*7U)THuUky@a(t1!S2S#@6FEg-rn}> z=AWyq=(DuyyuIzz)bo;+(T1sHQjHmZrCYPXrlG`Mg|bG+s&$Tqt8$|?qQ_wH?6#)N zW$Wdh>g1j8>9p_bw(sb(^6bTgsA6`iJD#<NuG(>Uu0Heb#_r~_?d7rT;;-=M!L{Ui z=GvC!*OTPakm}s3d$U61)sf@UkK)gb>DZ@@!Bgwrtm4p);mwQS%8BRHr0(Lq=+~y~ z-MP8zf4c61<<X(!&Y$Yow(R4uyzqqFzJS}je%iWy<IA4v<DBW?o0iO7=--*_;H~M} zsqpE-@8-bX#f9C$g5=GfwL|Xa00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0r^QpK~zY`?UUJC(?Ar(V^BbpRmDM2l-2b%E>$$61+gq;DJ?Apx>_)8HEF30 z1qv<yI!QY65i<h=Jn+JOn3sINdveZqt{_~`MdpTR4te<yvEk;e#wM}(cFUc+BHuEx zwXMCQQ|!8T|3SCNw~VdAT=visCNG}~>Uq@L_ZU6tfBI|y*^ohN&5&~$8Xg&a{sO&x z)%W_19RZglNiNj$_TBprh!c_AZnuPnKYkkfd})N~g^7GY=8#tqWQ@OlJIjk*1$#W> zgqZ+yzW-as^djR)gE?nn@}vi!H!=L<1mfjN3{M>+(=)SYCw3BX`FwNp6fe$M7+;i6 zP0Ts|#ifABKyWz}Ug1&^<UqvyH3+S)tw$+doagEfL}HdoIG#wRD2Vfr7JgcU0O^g* zUkVLzoGXry#4@R@lB0NWs^H)F^p4ffmArN24^hdfs+Omy80GW&f-oN{gjc}IE4D=t zwfMKBQ@nt8X1hFR1{zO;+2q*P4r#JhD$x<&c6oOh3TyF16wJRei2A*N&O&C(yQ>A* zTTdh_V86<|uIp4UMlA~aa1gDeGGHqKGqL&y^4bu#%6@n+eE^xPqU7u<Y%fNWHY$*+ zR%<FRl1?Nyv!GOKHH{aECXMoeS}PV0|3jEwtnxul(+=~OPV9QFW{v><WVgBso0Wk8 z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f?exDGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_join.svg b/web/pgadmin/misc/static/explain/img/ex_join.svg new file mode 100644 index 0000000..4256493 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_join.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 + +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_limit.png b/web/pgadmin/misc/static/explain/img/ex_limit.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3efd59d70436349e5413f8c5d2673200cd74f0 GIT binary patch literal 1237 zcmV;`1S<Q9P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(M7`;C&hL59?^MF-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUNiI=UKt$YscuhV`Hfo7w~d&?QwDGaB$~uaOH1r z;cjl-ZEe|XY}0FNhN)yyjTym@HuUkx@a(tm>$dan$M5O1^X<m+?8WZpv+d@x?d7rY z>%{Ehuk7Kj?BK2N=)$7LVC&_c>f@a6>b2?Mn&;e?=i8R-<FMt|ljYTt>))-W%w_1_ zndaG*<kXSm(~#=js_*Et=-rs+*p%bakE+va@8-bo<iD=jaL1~3vEFs<<gn}Btm)gT z>Ds97;k~rudA8?#xaxo6&Wz#Ai|N>>x$A)A(2n5BiRjm+=hmj@)urv<yUl57?A^NN z(xc|lqU_wb-^hpG#)jt9q}{@U-NAz8(4pSMh1|e_-NS_2zJTP;pYP?s>)N;G)1&6m zq2$e;<IJAw*|yrdedEiX37wJX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*pySK~zY`?UU_O5>XV!X``@E)R3}Nf|O*B$m)u`ByS4@xQIz9FPadbCWy#_ z5QxIR-d(t0;9^epp=NwO+}WKuzd83g&$%MegZ^zjB6tlvg%IMgSS)@*Je5c!L&VUt z=h9(fctj=}B}T`_$6pYFh*&O{i-`$^Lh+J#H90vcB}QJqnUWD>)6>#%;<hdmlBqj% znNi+NGuMdnZJ$&sm0G1%znh(%otvA}Xf*GU=I537>Y^pJA`vX;bh-upT-1Y}qNpWU zrdJHBuxd1!Er6>!B0rD_(XFkm>CkDl+JLg#?KIF1r;`Dr%kB06uIeHmuaQNo)k-16 z>!rcq^!bcncKg>^z*Rzst%U@<-VFmVK3~uTX8-!;P2>~V_R@9{;9VHHF1A>f4FRs| zBA?OE7vMGU#8sVnk=rDx1^uFp(!)}Krk7!LhhZ#WF?+&W5Q;>jF~C)w9^1QnUrFAD zodO!W2)fMJMPxr7PXMm!blKhehPqHzyFCE(hQql7Owi>vLwGZpj6gIVPo)7@b#KOh z^I4$5t~i`N223uuKMZVge?JO|R4R1<xT-gO?1Jfc5lbH&9`&dHC!2h8X_3C)(ET>K zCEkTm$i;CclRW{Uhm5oEtZyb+ez5U09OO<<^N=|!6gXkT=yIVYXK@xOl*Qp`v6z8u zp;Q`xnA|;C<PITUES_h9E0xL>VZ`DIvp*md{nbSlxu|lLN>vc~?IsI!LGL0Gf><J* zK7ylszIF^J7aUiGYNdX8C48}77w26U^+u!76h_)hp3ddaU~A`Rg$v-yWrSP~M%qh` zvMAR0EYM&p<#MBb8`9%~Yq_ZNF0Pu*=GEVt*n|Fa{RGa817HRj*Pj3Y03~!qSaf7z zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6W zZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjf-+GHC literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_limit.svg b/web/pgadmin/misc/static/explain/img/ex_limit.svg new file mode 100644 index 0000000..5472b85 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_limit.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABjtJREFU +aIHtl1tsFFUYx3/bnUsvIG1paw3VJxMTEARtTIgPNTGKSatBEm24aIzwrGK8RDTeohJFQX2TACGC +NkWDRFsTfHKfSAiUixQfwKjYKm0pVHrZ3ZnpfD7MfWdLpxR40P2/7Ox/zpzz/59zvu98B0oooYQS +Sijh6pFK0uilrw5J5pwR41tu07je/JY1yxNpVJI0ypwzWP7gYnpHTJ9bVqOR+fEkDzy8hDOXA/7u +Wo0DXSdY2XYXv49ZKClQU8Id8zR2f3ucpx9bSv+4hZ522t8+V+WTfcd4/ollnJ+wUMoc3bdWKWzu +6EkiL7kRgN4Rk8xgLsaf+segZziYTT3tCDk7anJ6JD7L/eMWvSMGahkoobk+P2Hx66jTXkmnExvw +kNjIomo18n9ZjUYGuHOeBoCeSqHKJIvmqZzBmWkllYqsyCFgQZUzZHhFABorHT68IjNBbP8dXL9e +Rrq6ZtTJjUR1Wxsrdu6M6Y7ZHunqYsXatbMabFLEf7ZEUFIpLJezBWyi76d7BjDc/6e/+abomDEj +1W1tHPzyy6vRf0NQ3dYGO3fG+JiRow+lOLKwjOamVja170gBZLbdK/c88xmWeSn4UK3h6K5nCfMi +gqLU0LP7Oe5++lMsYzhor9TS88XzLHtyG5ZxEUFABEWbz/G9L7B03VbM7BCIy5fXc6LjRVo2Hk4B +vN+5QY70ddPclIK4j7iRI33drFy+ggOHuiO8ZV7CzP8d68DjxbYdQne2gGUMY2T/8tuJ5vEXyU/0 +OYIBsZ1fMztEfrzP2Xv4r6fVNaURAEVTi9FFISKBiSIKPKHBaxtEAt5rb9tgC+KuiNiTM9JVlljx +VCicuhAfFivimBW7wEToe9/EVH1eAcVXRNfinFoTGTCdrnb52kCMCIpSC0BaqUUrxzegaPMBUMvr +AgMiKHqd016bj1YRrIKq1yfSdWUjBUuoLWjh6K5nY+20BS307H6uKH9sz8ai/PG9LxTlT3a+XJSH +w1Pqimj2HrysAJBWnQ9WfXyLNDe1YvRnnCxkXQpmUpvvZKenPsEyh3EnHkWr5diejSxdtxUrf8Ff +LEWt5UTHi9y1+iOs3JDDi6CU13Gy82WWPP4BRnYIryNVr+fn/a9eUZeXVSNGjvR1s66tnbSqklYV +NqxZT1k6zfY927mv7FYs86KftWQyCG4zP4yRc7NTKBbM3AWMif5gz7vbxsoNkRvr83ndbW9kh8iP +ngviZ45MqysMP9ibm1rZ29VJWlUoU9KkFYXte7bT3NTqi4yYCAekm7nEtuO8iJ9SwQt22+nHFn8l +Eds3IbbtB/y0ugqNbGrfkWpuamXXvt2kFYXPv/icwuXzTEhIgBBOmRL48MS4KdUXKZ4Bz7jbUZgL +zVMSXVAQ7Jvad6Te79wgxRorSi2USyQWwNn7ogdbTVFdXq9zVwQ/FsDZ+2ITiQUAtaLBMey21yqC +rHUlXR7+29Xv/atXA7OvVCNc+PSfBc7u31+UL1r9/tTRcU0GvR6YqvpNdLHPbLtXlq7bipm74BDu +OXI158LiVZsxJgaCWKhs4NSB11j06LsY4wN+/1pVA73fv+FXv9Mh8X0ydi64W8XMDpEf+9PPUP65 +MDFA7vKf/vdS5fD58QFyl/8IVbnOrzE+QHbk9yDNz7DeSn4xDle5oTQr9mTkrJCCUJDC2PBSsne2 +FBSQV1MwwgyNRGYxPKAdMllwLjhU6LCLnCkSWQHPhIT7u9ZGFL3OEeCWIV7Vqur1kZJlynOhsgEA +raLBmRBXtFbl8u57z4A+p3FGRhIF0qF9L4nRn4nx2oIWrje//Ikt1y7Yjf4MS9o/xMwOAs7u0Srq +Ofn1KyxetRkzO+hvC7W8nlMHXuPOle+RD2ehypvp/e51Fj3yDsb4gL8ztcoGTne/ycLWt8mPnfer +AX1uI7/88FYSecmNAJjZQfKjfbFYMLODZC+fc6kgFvLjA+RG/giC1+PH3OxENBbyo38zcfG3YMAZ +xnxiI2JHhRIJ3nA2C19vg5tgWFnhPd5tPiskv7NPUWYH1a74ycB5QSSlBuk6SAwyOTl7By4Sr4iq +18McicQCOLESbDcnFgC0yvqIaC8r6XMaQykXNDc76XMbI9tJv+l/mrVKKKGEEkoooQTgX6YnVtAh +YmJfAAAAAElFTkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_lock_rows.png b/web/pgadmin/misc/static/explain/img/ex_lock_rows.png new file mode 100644 index 0000000000000000000000000000000000000000..41c1148bb185c87898b3fddaa76be36a15703336 GIT binary patch literal 1520 zcmV<M1rPd(P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700078P)t-s1prKL zYin<9ZE<dHb#ijIWKo23T)1UXxMxwgX;FK4c)Ds)x@%E3h{3vUQGR@Ux^Yo}etx`j zQG<Yhyme89f`YwxQHX|yzI;)Nh={*{QH+X;38~`0f>Di(jE;<qz=Tnbj*fDcp^%S{ zz=%=8h*6S~l9Q8@!H+hYm3+dEQI(aIm6n#4mzS5An8cD%#F$YswdI<go|~SYb*9Ih zp`pT_QO2H8o};6lq@>5AQ9-=u%c5Axr%}nMQA)t+%BxY=s7}hQQOB=S%&$?Wv9Zju zQmC`DUBv4BtpTdFwW_wZW5(*uwpDA#=xE67&bnBwy1LG~S+BgjZp-YjzP@$M?Ap72 zw8FyMy@}(!bKJgw|GhAK(eJjz#N5GxgwgKZ!-Is=@ZQ9P-o}QE)b8KMhu_GEk=5?t z$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+m zlIGK+<<^tt)THOtrLN%f=Gm0!*QV&#r{>z0>Dj2~+?VOvsp{Fb>D#L7+PCQ5nd;rD z?A*BN;F{~+tn%Ha?A^NS->vfAr|jOk^xmoL;H~Q8ob=zR?BTBM;JfPNo$TVT?cu!i z;i~N8u=L}t?d7rb<gf4KzU}6+?&h=a<-qpkvhe1>`Q@?i=(G0cv-an-@9DMq=d<wX z!uaU6@a(qs>bm&qxbf@6{pz;(?7H&p#rf^N`R>2@?#1))$p7!Z`SHN{@xlA?!~gNV z|MAlO^v(bC)c^F+|MtiK_R0VD+W+?3|M<<SyU{8D0004WQchC<K<3zH00009a7bBm z000XU000XU0RWnu7ytkRE=fc|R7l6|lj&CyQ5eRxeH+_N%WSus*<!m=*`Bu8B8iHI zC~mlcpojwm1gMN_hN04AG^HkyMp;_fzWiC;xpx#ij-Jk`bLxZdhi7KancsQe=eh3< z3Yw{ZPzMOMrc^$J5DEl>R3a-OF)@e8xgr!66UABC*%d@ZUSZ)af)^1)L_`RP1gMF` zrP$b5A(0C4Y$7i?Sy)K?L6_Y-qqanb<M+*I<|&mUcAZbVnRe~SO7sCn1_lO3#?<5S z41pnrVSK<x)3g_0A|~ZR%)0Q%xVS|K8R+b6_i*ZIY;5cUjNNMO2DH(rb8yJniyPR- z(tX=Gq#Ysc7_l>ev0AM(=rZcYkf@Xxj4t0ln?*eB=x3yTb~{A6t+$OdaO!GmS~0Te z24{TE!C>SC%|Gtq5pvPx1ztyMQx8I}?^v_?^qCXK;t$OVo);YybP}+Yfi!)xvdGo< zqo2Nf{PF$s@L+%cR@fzzEilx_FhjuC-A(&|*XeNdfF6pX+^Eatcca5>4G#A9K3UHq zNl8hW0WP{&7u8LGQYjQRgq(YWkWm(S7&eYDb~_H%=md_M>PiYw3PmYKPQCUc4?_J2 z3YJE}wpOZC6sRjLm0J*U{FNWMzhd0WWEXCm#o|Ip{0l#FH{`bxJN%qQMiFvnG3?@_ zyPRH5ds>^|S-9(LHaBpY&8802W$)8xFF$<!`R#4*z2@cx5W(|LbRmZ>%tZzHdW7tW z-nMaVSm>%{Axjp{p9>MEP6rnQE2UB?>VQoymz#m9AYY~jd{+!b+Qcai)*>$|G6923 zCL{R~I6w86Q`UtGx-c0!K!=_rTX>P90f}WyPLIC}Mb){v)4|$d(Cgbki&j(Bz&{wC zAMXHG=pvT{8mUC0=11^i1R{D_u2c)EBogry2#z!mA#<hDDxj8##Y%p}ZLyeL6TGx& zG*$JWUaeHt|Fy(iCIdVLtZgKzZ2=8xwHkI&mY3J^4~7>5D=9@T#H@>Qkw{d=j~MdV z#lWgX!TOOBenbyXLCdK|!XiqsSX2(mrbgOGEu0@~po`j)l9JkK5=)=%R?gJ_Sib;} WuicyymX%Qe0000<MNUMnLSTYGrAb2o literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_lock_rows.svg b/web/pgadmin/misc/static/explain/img/ex_lock_rows.svg new file mode 100644 index 0000000..5889bcc --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_lock_rows.svg @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +z638y17wPvQAAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_materialize.png b/web/pgadmin/misc/static/explain/img/ex_materialize.png new file mode 100644 index 0000000000000000000000000000000000000000..c3bd0bb90dd2ef1cc1baf7f932817d1b6bdf463b GIT binary patch literal 1221 zcmV;$1UmbPP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001^ zyUc^E$aSX2Hi*HV&EAa1-IK}Ps?y-H)ZnGh-mTK#zS!b$%<V(H=}o`rQ^M+n)bNzp z@OsYdhtuw@-}7s{*>k?y5Ub*3#pqna>5|p&pRKHao1$`-p~$a;;^52R-owF<HuUhw z@a(tV+qd1?w&2~u>*k;8<eu;8wd&)Y-PyJ2;hXR1v*6sp^6kaUy`#sfb>G{;;oZva z=CbkX#N5}k+|{$*+Q8@Bm*&}&?BlTA*tOf#vFYHN=--*_;H}=+zU0-B;M>TCsbo@( z8Sv)7tJG}W*1h1`$FJLRv*CB}=)&sVtLfaT?&7`L(XZLhuG!A5qQzgO%Ve<JbGPSw zxa)u8(U0QJjOp2^+S0Jx)VsRuf#J-G=+~#%%&gqgy5P!*=hmj**v0JKy4%va+tIk@ z)THLqqu0r)-^hpF#f9C$g67eo*vzZg%d6JMsM^oB<j$bnzJT7<!|U0$+RnGy&9~&u zp5x4(<IA4a#irW2ecQc%&=gc%00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0(?nCK~zY`?b6p*8bK5XU_ww#jGAI1rVXt0A|?yUN>Pg78bgs7LkqpPC|yAQ z^~}hc;|y@}z&Sa2@IKs^*>CRt?k<n_Q2(eN@lkOdJ9#WX#r69K{Ds9u;S&GJ)1~ES ze2fTIR@a`t5WIY~zW!Q(k;OL~8$t+$3(Evq6^TTff|a$mo9_g3PI><U71uHH@iqn5 z?;ilML?RJ$9V671R4U!#Iz}WinM{JZTtN`2QmK@pu2N4Wa``NxQfX!ot#$^{Xmr~+ z;j$<c`Wac&>g^qjd;+Mrj*-t4Dy|b#6bd*+Pt%5pDQfi=wPQ3IcZn=8g&xp*CKE$u z(db|b<Nm(cf)j<-YNY{fGTBI?)*T!gAu*fn1hHE8Xuz0kHU~)#4k59a%}#=dX_Ugi zI2^7!a^yZjWSnBxZnt~>x-s`LGP5^kU>L>)TrA6;0C@jxeL01O+O=3LUn!5*>+|C; z#@J8_HgFbX0nh#I{QUU%`{~6GH;+r<4TZxIl0>5{V9$cV*q<pEKhYGs)9Lh5zHmIA zz=<Oo2tX1{CR2Cu-AEu33i+r=Je|(qWSk-!OQo{J#ynmhOyN&tGP$|`u@jb!WkEKd zFJy^N>4`)VekxZimGCKCihQ|TE)WE!sAQ;OwN|U+B$oVjnFob(`Km#XM7mNfQuSJ` z*2GEb@)F)(xVoAknM$=<f~3_V2ujfg?M9=~CJ0PX&rzLbv)P$@W7$Fh-rw$adlOUY zb$Ea0x<A0Da4EXO;jl-LdJCoK-`v~`aMFOJ3wl#Xvo#uBQ-i4lK0K9-M)2V&WSpYi z>rG_o^ihh=U@(|_V-NMe)o+jt(ePu5AK?H103~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfVJ3t* literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_materialize.svg b/web/pgadmin/misc/static/explain/img/ex_materialize.svg new file mode 100644 index 0000000..c6845db --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_materialize.svg @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +WLxZKdhpAAAAAElFTkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_merge.png b/web/pgadmin/misc/static/explain/img/ex_merge.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd8299fdcb72604d0c97816d38ee25ec51699ff GIT binary patch literal 1127 zcmV-t1ep7YP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001z zmC<Hv(ap~CyuIwd!0pk|^3&Aw$H?!;$neU_@!Q+=*4Opn;rFJf=Bcaa!NTsv#qYJY z>$$q@!^H2!#_)!zWKxY8p~PNwrpGpj!Eep(LA>Zn!0CI@?}XFvW5()e$n0**?3dZ` zpxg0;(e8}Y?vd5*uHf?tsp4J4>N2(Eb<ON+$LOQSVRDwC!H+ic@W}A&w(se*^X<m& z=CbYOvGMD~>g1j2;F{;$m*?A-?BlSe%w_81oao+}=Gm3(;;-o4nC97(<=2z!;H{?6 zXYAmv@aV$Fs&%W?Z0p~x>fEaD<-p_8kK@pe>DsAbl`meHCBewL<kgaJokg0;U3jiO zp0$U%?SbUekm1dYi>qviyiJ|ZV|uVayzqqY<iF|Ir|#mtzsI+$-f_6=fAHqO=+~#` z)}`&=yWz}=;K+#I$A{+Bq~67a=F_9#$%)>?h26u0=Fy_;-MZ$|qU_wb=Fy?$&!Owu zx7@#g+r59}&Y<1Fg5%7dI?;o_00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0v<_3K~zY`?bGX5(r_3DaGDn~EzQc+f-=ht?ef4F_ZT1uwF%R(Lb^=WWfKN0 zFq@$K>;1-ob697`-_$p~@OkmP`<&<Z{qD@+xE#k7!Wh%W5n^n7Vq%hTUY)u&O-wtT zGuH_$8NV?*J4f7{pT9LmOy0gTHS@oavu8O+V;7hOa^b9myh~n)+@p*!Z5*NQyWH*v z)WgL`OOL51%THIHQCQ;gcsy=ub#2Y{oLXL8e6fNj_O84fA+P%HH*FjNug~Z6f|sUg zKlm9Y5Ckmog+d`3=x{j9027HuW0vIgKO}AtmSrFiO(c>wNIZ@R!?LLW#1iZ2j3wDH zWf`OhpcKJmHj~4WH(-ouTamY;SNt@?_#qgJC3BGDIDQkbgke(=lwv)NQgHcvL9ilQ z8{6+3!+!vnR0I{9Os9(+@P&dk*?IrrBQj*kFsRrlDmGgz?(&F~%a-KR=PzHkNs=sy z$c&`egFQj0NLJ(<GT(ocN}?!|HXB1`XA4~s`&V+=4EGZ@c|njsl4WJz>dLS<v7aT= zPa%}c)e6WpRjr>w290sM`GP^JRT&hu(P*AR2H%Cx8^sD$O;e!W_|<CT$uNb2QXDjY zw-2$zW@Dx+l2DN)*ss@{2XOdD*N^ZIt7uwnm_qM#y2p4TYc*7Cv(-A$5$Se&c%rB( zDz@D^>F99WwM7OgbR)%4uh+w8IY(ocV>y2TWnrZACmaDB0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1n&OPyYY_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge.svg b/web/pgadmin/misc/static/explain/img/ex_merge.svg new file mode 100644 index 0000000..eb44bdd --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_merge.svg @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9aa51fce9d775f169f70d115761e9817541c48 GIT binary patch literal 1599 zcmV-F2Eh4=P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700093P)t-s0001` zsN`mA(ag>9yuR$dzwN)l?a<Nk)710F$nVI>@XO2b+1mBo-1XAa^VHPz)z<Xk;rG0~ z?53#ZsH*3xtmnbP?#0FLw6*HCx9hpO?9I;d(b4k5#P7w%@W;sT*Vpx#ym(TL8KJ~p ziMiW0h{0H#%Wuu@MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!a!0BPe>vqlTrrz>E zyy*w1;t;Fi8m{AA#p`j)>`uPsTEXXJ#psgN?-HxxEVJZDyyl71?xMzDdY-9bilcOk z)uYE@!H+id@yYP)xAgGH^YF;;>bCFcweRV)^X|sL!S2S#@7~__q{(9I=AY~3p6~0n z@9MSb;+yH=o9W=1?&q_stmw0}>b$+})YS8(%Vg^0o#@}0=-!#`=CY>EX7KE`>f@d2 z;+*g3v*_KJ=iHa=<glpEX!GsH^6bU!=CbYOvF+oq@#@2=(rVkiiM5%2tJQ4t?#J=# z#O&j*?BcHM;H~iI!M}zvzl?*mVn4J?6S!qS$(4q1X1J}_Z|L5b?BcKG*OTSdlH}Bp z<ja`1U>nIz8rM-G;Z!G=R8sZm;b)sQqtRwwm?i4*<LBF!=Gv9y(~#rRkI$7};#4UA z|Nq*iihHO~n#x^xu0Fcaqq*#W=GvC#*_Gwkl<VKE<I<4h(T?KKjlO6w!*D~Oz=4Ol zOq|YPdayvc?t;7TgY4n1@8-bj+^Xr@s_ELPv`iG|@85{MPM*<ZtKM<A>wmiJfxPg9 zwO1DE-K^@}tMBB$?&H1b*{A5&r|8$F(UxcH-mK!!jp^8@;LC~N$cW#^hv34I>fNg1 z&Wz#BjNizI-^PaC#f9e6qql^BuwFj0N)yD8gyGDK=hda&#fIL*h26u1=Fy_))~4;> zyX@Y&=Fy?++qmuEyyn!T=F_C?-MZ}DxaH8H<<Ftz&Y<hsx98NP-o%95zJS}kf8@=d z-NJ+2!Gh$@pxeBD+Pi+^%%0r9f!x1=+PZz?%bw)UpX%ARsGOc$00001bW%=J06^y0 zW&i*H0b)x>M4bk^^05E_010qNS#tmY07w7;07w8v$!k6U00L=AL_t(Y$75g^1&mA} zfI<?|!o<wN%Er#b!O6wV!^F$SFCfT7P>YbTh^QEoxP+vXG?R?1oV>zd(L%ak$OthC zfTEHjsalkjl_=7pq6z{KQVqf;q(xO-LsLszRYzA(-#}H}(8$<Cm7o?=Gjj_|RV!;7 zTRT-#dk04+!di&4#TiM93)uY-(iI$8ZrHTABWdyQ^z!oZ_VDrb^AGS~4h)hG#+D?M zLXfq1g@%TOdqhM=MaOsu#m2=aVAYa{q9rUWDZ;})Iyog3kCrrKE$K-anf@MG$=Nx% zc(mjpYw?Nj^UwDvC@d;2!Q+=wBrRngAOIoDaVBr23S?U<vtm-KJW8r-YU}D78k?G1 zTCr(qL)H@0o}E+d(b3t}-P7CGKcT;G;v`Hhlc!9b#sJF$9;rFgXLNYfcFmkMyKl~% zxpU|A&BN3(f5E~<Ks`!}L3%uLmn>aY>#=;r%2liT=YaI|uff!^cHR07Q<apIHf{py z@hIuoTwCX{W$U)>O%vvV^i0@+sb%NdUAy<}-M4Ym{{2eGA$FjDE=UhHTY!4zPX^io z)B&`mZu!AOhdquQJ$C#=AIK|M{Q?WP{b0YGoVDuIc8}9%&YnAuJH(&>8e$htUA%PK z<M`z(SFhDyzj3qiRx1Mm;IZw}?K8(c?%ch1{{ikahN|Vr>0=Kcc|5-M;K@_mX$%Dr zm&Q<Sd3NXdi<cg+UcY(!j!0WP-e3K2|B1(&kDoq$Ce|<4?tl6E+T+`&?>~MLtL4Gh zU%%gaeE$C9&tGD-Jbm-_-#d^0KmY#yPrDEs1=s-qCgT-R!|=q?0000bbVXQnWMOn= zI%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4Wjbwd xWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1n5vrF{SZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.svg b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.svg new file mode 100644 index 0000000..ac395c6 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +RK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_append.png b/web/pgadmin/misc/static/explain/img/ex_merge_append.png new file mode 100644 index 0000000000000000000000000000000000000000..12fc55d76f504140935d5fa422f9a5075431bbc3 GIT binary patch literal 980 zcmV;_11tQAP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005JP)t-s00000 z003rd(Nc{WHi*FosNxW-;$)T3a-%gGuH(UvHg>8zdY-9xu0FMyetNM%gs???v_por zNkF{mMZW2fwrozm=1joprKsemspnI|>RQ3)jlolwyLFkoc&e=DiMiWd#p`6n=&rBn zp~POI$6%JsU2)6oq{?G&&F-hoW_r%-+rEF>y@|ZN?A*VB+`xgozwN%i?cKqGgVF8X z!h^rT?cT(M!ou!_)bQTLg~G${i`4Gl$A*&C@5RRNy3wP>#_+D%ag^Bb;mnHS&yCB> z@#M{(<j$YW&GF^VpySbw<<Fqw(vQy1^0ec5<kOJl(V^tjk>=8)<kgbV(emchr03M6 zw3*OTYfrLEud)710S)b!}rrs&tF=Gv9%*r(Rk^ttPQ>Dj2~+?VOvsp{Fb*xB^D z?t<yus_NXT=--*^+qmiAn!NCY>)x#C;hXH;y6fMq?B2TS;+*W@t?c2h>g1i+<;(2i zukGQy?BlQO<FM`Hu;AeL?&7`e<gxDKzU}3)?&h-Z<-hOd!0+g@@9DJg=)v&l!td&~ z@9Vbl>cjBtw(#t?^6bU)?Z)%($Mo^Z1Vq=200001bW%=J06^y0W&i*H32;bRa{vGf z6951U69E94oEQKA0kKI$K~zY`?UPkg!$1^;v)KUULUEU1#ogWAouV!7?ykih{xC_% z08P8uzzo9+=i$EWd~@#Ev&%65`jNspQS#J=aPdC=LHS%|Vph=rrxEdXaCDB~V*P?6 zOSoTiagtKVQ(H*3K0T*!kezPn9y(&R*|RBuD5{jL$;c}oWwnJQBj0x+hE!(ZG4|b2 z56J|uqU6ai*kJH@XNdN;E;@msASoyeeLdlI2K-Hg!O>Vfiyb6RLfk-<JSpwt1POuH z$A{Y&cse`Wy#}=#6BO#@!i&hmHd?uav*Et3WuQFNGM5Uyz`)%Gnzz7yUq|yS4PkhF ztFRheEux77*lcU89;dqKTir#MXUoaK4P4Akj_d*D?}vtngvyQCK3LpK>BaV2;4y5! zFcp^>3gRlIkf(HCo=X%&Q8JG`mtuU?vnWc&GXk+=|5<z>)+K-bO1R(MTt0_mbAQjO zbuYw{VGA{*NiY=`WVb62QpvD}s*xFtx!GwA)=08cuRN`gIaG!Ep))fzsaD}aS{Y79 zOvZIsXsWB7QXr(2iS{Zh6GdK`j1X5QioEi_{zPxhzn!H%4w>%&0000<MNUMnLSTYP CgEgxF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_append.svg b/web/pgadmin/misc/static/explain/img/ex_merge_append.svg new file mode 100644 index 0000000..992ee02 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_merge_append.svg @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce4839e02fd3f17b5fd8e358ff204046c38d26f GIT binary patch literal 1344 zcmY+CSx{347==TqEn;1Yb)kzRwvO5s8xTS1=pdpEBQS_s6{;)(R?#BJSj4Jq3RJBX zQDkYPh!_@AR0IrxkdTEC5=cT4vWF~}EH}AX?oB|$Ort*a;rwUL%=w=FQ<a$T<6{5M z{81>>;#h1<lGj7u%Fow(H%%9op-|{MiE#(_c;jQdE<1-e#<7zI!9lWxOtDPx9D+$F za|9Y;+1PBmM2g7e2w&iwoP>oUczW7R8US1I0KR>uy>o^_wbJQO_e)bxulW@b<ZvB4 zo@1B>(HS=8h)pa;>PUr2w*vp69j|&N3$LV{>k!lrt7&peF2@=_WK3t6FL1zCrK1;c zH7nuAD!5GzQ;lwx*-Zivior!Ux<t@i6v-ISq51BG4od>61lETNxJ+QH5ZZ2v>;w(c zr$;)~&Sx6uh{@f|NG-y(<=?}pne`Kl{^u_ZM7rq_Go5lf9JaG;VDH?l&W*_Qz^qE` z(rDcPFl)8GZeeAZfrp4=T%kmSLZ?ImE0ivyaqclYvz3#LAOEF|e_A$BCFnXQ9V7Dv z_73408`uMxdz=u{jY#L*+Na`NlkRVmw$Z4rw*oI<I~TTdU}((ckeqDT`iPf(toCb@ zT??6djMEJURo#rD7SwjRVJU3mIH578m5tcNm+*=8qsIyfJBhqUufSr+@WP;cFeAGU zOx1wur*5ajX&H5xSqLO*8Y-zE#x-)&i@KtYKUhz+mi9wsb~6oB6U@p^NJpMUrV*>q zZCA}es>*=`951s&nb&8&N(4(twsIRVWR$lXrFet*iAB}#cBo*>Bn%3iW`PS*7^Q7$ z_8+Q|3MKs-z-xxVNk~tFw8K^n)nS-0h+9>R>&oGB1*KF!-sCj%Aq~|!O|hzn95ds< zWQ&4YCLb!14P4c6a1JBSs-{>}Ll!034sgw~K0UWdJBBk&^&l3R0~ojKxv*KPW#gp8 z%b<J^8ZM=HN9j|LlyCqQ1x#go!@_geqvySjeW$&woSohR5F4}WAeMO|ZS{hWZ^o@H zjt<~cX=Bt;2A4)*(K*93HuL+nBQc3L{_3j4ufE$?-cl2G_hx4!iJHcXCZ>+~h4>dY zSFdYJuBo}Vk>A|xk3MZ$+vF3p@YH_cBwxfkBosto!jdAwL$+=?ya7+A@<*k6g(9w! zvR@G^meB8Yt<;>!+s)T3aowoc;8%FDtaxd7@E|tX<MBnKJ@e?Y(o*z}vfa_c)PZNG zs-i>z%K`%f)vG>Tv0{ZT@XO_&ueyC`AKI845G$^ZA*NQ}>28@ViTY+6jXxB0|Ihe+ zAGQbA9hF3-<mczxr>ZM7wVqPyI&zbynjb2^vgu!ZXGXE!his~s5{t;!8Lhxdd2+H$ z`a^M1P2{d350QAO=#A%f!-lxV@)Wji(}5@Phm(@(Lzd&2xj)T=+t1GfFXQUTsNU3- z3CFt&S^TUm*_%@dF`1P<NcVl;vpy!2^m&H9U6|t$5mLzMU;Ubr=F|HHSR3Eadqx5D zUS@KS_2<1=;NKL~a}pYy|H!jsP2}&ojk|&;3b$YI&{zkqJQ;7?@f+?)@T$!?Vu1u2 z6*|R)<?x~pmIY>P?D=^xPs_+6o5h4r&fZYnYKX{H+WIe;MNe~RudnS)#<~{;28H`~ zp;7y0eV6*_*%98?uP@khq#!fBAS?1jewNozp_mX%a7bt{Cgfl!CNgYGWLVg@n5~f* t%(lAqYyJnE&CNWOeepej+5QfA+m6J9zXwKZ4|RG0RP3IF7(#Sf>3<opDS-e0 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.svg b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.svg new file mode 100644 index 0000000..3af860a --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABUBJREFU +aIHtl11oVEcYhp+ZOWezm91NsjHqbrQlW2OpgqbBi2JUCqKkvSroRQu9ECxUtIiUSpEWijcFFQIt +pVILSlMoLYWEXhQlVGlEoVCwMUHUqm1qK/n/dWM2+3PO9OIkm8azCew22aYxLxzYec+cmXlnvnn3 ++2AZy1jGEwGRjfzqmwf68pVBF//ijhXkyr/+2tqsc8w3jGzk5SuDvLm/ipHRFFIIhIRQmcnpzzs5 +fPAZxsbSCCFQUlBSatDw8T3efbua8bid6R/wKz48dacQGmYXAjAykqKvP4mUAilBCmdjH46mGR5J +IaVAKYFUDv/okcXDmOXqXyjIgs62gFgyQmYNrbIyEwSZmC8tdbqWlBpIReaOBAIKAL9fIaTI9C8u +LuweLRnXerJx5uIxvachos9cPKb/67VMIa9Abmlv5JUXdtPS3jjf68kbs172+cbJlru6qa3Lxdet +K2djOOjiN0aC3OyOZeW3V69w3buCCWlq62Lr7k38HktR4ZGsLBI8H/Lw0bdt1G9bR/+EjRJgCIj4 +FDfv9FLz3GpiKRtTCgwBIY/i6o3urOMXTAhA+3CKjuEElV7JWp9khceJ7J64zYPxNIYEUwhM6Wz4 +cNJmKGHhkQJTgpojWyiokJqQSdAgcyJP+Z3pwz6JEkbmRCqKJANAyCMxBJkTKTFnv9J5CxEyt7+H +Xat6uPiD87t3kmsFtgd/Y8P9X9nwWP8SFeXPn70zuEGgqqw46/j5CxG5GV79aAPvHfyEdGpoenKz +nGvnPiNS24xtxTO8VD5oO8/K2h0kkzZKCQwl8HolV38ayjZ84U4EIJ0aIpXscfG2Fce2xlz8xITF +RNzGMASGKVFq9jnzToiEXFz55pIRkndoyTyEGGZ51rZUvpljT7a9XpUp4AwlMM0FsF+hchNSuXkv +184ddvHl0Tq62867+KS5no62ERdf9bTPxcG/OZEchXR1NLFl/5RrabQGwwjxyxdHePalo5Ou5eSg +Uvrovn6BLbVbF961pFQ5f5NODZGc6AKt0ZaN9liA41pWOuYIsTVaOYIW3LVWlqxlPBnHX+ynb/Sv +Gan8XCm+th0BdtrCtpzHeaEdcbZGa43Wds5ryktIRXAN8UScNasruf5H6wwxLe2NHNh3gJb2Rlxi +bAttWei0hU5Z8A8h2rbBttGWDXbuZU5eQtaHaxkcGaa6ah2tnWc5+vVO9jRE9J6GiAbHmg/uP+QS +I1UIwwxjmmFMTxhlOK4lpBepAkgZQKkAUk67VrFf4StW+LxyTtfKq57uHu7ULe1f0mNdY1XFKoLB +IMFgCVJIkAIhnAfg9NlPaX6nW9y9dFJ3dTS5xiqP1hFcvdHFJ8313O59PANzXGvzptL5qUcioahw +xMDdW20MxNrpf/gg8/7QG29lRNTX7KOZE3R1NFHz6ikS432TIaQxvRXc+O59qncewUo9ckJMgzKK +6bt9qTCuFQlFs57mVHhNiTiw60SmX2Ksl/jofeeeWDbeQAoAK/mIVGLEcSytM26Wi2vNez1SX7Mv +qwjAEZBKO9ZrOw/guJRloyfdC537ZZ93IVOLb+aE6509ab160p0yQuxp63XCaxEImQtmUQU6kEZr +G63B4w8Dzp3AY6PRoEGZAaBAuVauqNy8l5vff+Diy6N19N/50cUXLNfKFV0dTWx4+TiJ2HRhVRQM +c+vCcaLbDmElpwsr5QkwcK+1MK6VDxKxHuLDnS7eSo6Rirt3vyAV4mLDkhFS0NAqCoaztpUnMIOf +ai9a17p14biLL4/WMXCv1cXn6lrLWMYylvH/wt9XlkmZoNULOgAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_nested.png b/web/pgadmin/misc/static/explain/img/ex_nested.png new file mode 100644 index 0000000000000000000000000000000000000000..15c47316d5d4163d97b95cda99b2e3a2049341c5 GIT binary patch literal 1108 zcmV-a1grarP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002N z!qAqP(SL){b9d2ZYtf>m<h8fzyT0th#P7ht?ZCnA!NTss!|uez@5RRN#>el+$nVI> z@W{&W%FFS~%<;_4^3Bfj&d%}9&+^dF^3v1u)YS9U)%4fb^{cMtuCeH+s^-7I?YX<_ zv9sxtmEUxE)|i{&!NTpPsL;d2(7e9v+1d5IzwF1wx2vUWos>nDi!Y6V8N<SK)!C8X z=A7p9r{wXW<M5#4@SfuCp5pDD;q08@?3>`~o8Rb}-shO$=$_f!mC@3Tzr1kL*o)26 zebU;8+TxSc+KR}^cFoU%&Cc<&uw0mqEU~Ov&d-F$$aBxniISDkwXlcC#=6<xjNRgy z+TW7e-jUhekLvTc$jR@iqGZ|JkFBog*xQf2zwOuBjJLS!xVh`s*o@`wtmEsW*yMoL z*Nf}&z3K0|)z^yM=aJRciPhDL-sP6m)QFdjE7;qU%*}nTs8!L=iO9rx!oF?G$b{0> zhS%DTytZrH;g{Fej@H)nL!K(600001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0t-n*K~zY`?bYj3+CUHha0E^Sm0C-!f`UTD2bF{cA89RMMd}k-_8X`@6D zMDcCwzpmmq!zFho^0nPBncU28_IB=WSEKnK57DI6=@B#ZI&Bj!nhh;RQ)^pWyU}cZ z)A6?RoyGFL>qB>s)oQibdVBlq-DU@7w9Wkk{RS54bh=CqZ4J>G20jkDS^IJi4ZF;` z8lrbO21iC&#g2{)nR@g!3&`nlGsS~(TRx#$;_)EO3xVtkGWPWA<#-<`!pC#oDzTG@ zm-7e4Cnl!^LHPV-`fD&4425UD%|;##g>e44==XU{gcqWVOA$^@mY1u)d>}fv62tcu zi?6P&^D2@+DDn7(31MX;iI<(+h;RM?6?qPr6k<u`VluY5#Uwyj-DZ&~GD!iwmYp3E zNvTN!?e11h8X!#~86`=e_H5Spl!p|M$tel4d9vA`ebie9IZ>Sj{rZg<Sws=27lu-c zC{alo_Vx${Bq~Y6em=jiHXz9~0tdl-K6I!$8ITL~EO2y0s0Io}dif9vlTN=_Vvz7L ziImF>GJZ_B{3m6ZPJE}8xcZ5m`Oke+!p|<Q#uX3w<m}?|il?`W$kJNndTTqC$=!&O zB+G?jsp7x9xaAm4DY72;gNf4L^Q&7%Q+ieFtE0i*;iR56euwqsx`u@l8x{?Wqy`3G z1LL)UA^xw%J#C$lG-cRqEC2uiC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$c zGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLe aHY+eSIxsNGmsP9)0000<MNUMnLSTY)!c1@g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested.svg b/web/pgadmin/misc/static/explain/img/ex_nested.svg new file mode 100644 index 0000000..9ff1db4 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_nested.svg @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +pGM4BAAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c0763337617f9ffe8cf13ba0f47f4cbc228c5e GIT binary patch literal 1741 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.svg b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.svg new file mode 100644 index 0000000..083e373 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.svg @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +zFy1AyrM+wAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e8a17d409343ea937e43ebb76e8ebce3cbee49 GIT binary patch literal 1679 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 ZD=;-WFfhuORjdF2002ovPDHLkV1g+E(G&mx literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.svg b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.svg new file mode 100644 index 0000000..48ec1a5 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAACFJJREFU +aIHtmW1sW9UZx3/3zXbs2E7sJnWSJm0JjDaDhEIRojQKHxjVhLZpdIyXQSt1E6uGumlCSP1Gu01q +mVaNDVUCNJASxqhgnSo2xjp1Ul8m8ZYqOGPtXpo2TZs0SWMnthu/3etz9sG1E8dJaicpH0b/0pV9 +n+NzzvP3c57/ee49cAM3cANfCCgzDaOXU/LYiRD9/XHC4yahcHpBA/t9NnzVBqtWOelo91NbYy+a +aylRMHiORCIhqPHbsNlVHHYNIUBRspeqgqIo+U9FUVAVUFRQFVBVBVVTSCYyxBMZhkeSoHDdyejT +b3Ik3G6dSNTC7lCx0gKnyyhr0GjUJJEQpNOCZX4bY6E0x06ESur7wuH/yoM9Q0X2Dc0+WgLuIntL +nZuNN/uVAiL9/XFa1nqIxSycTo3+gTgDA3GiMassIl6PQfNNLtZ8qZJkSlAXcPDBR+GS+h7sGeLe +r9zO2ZjJMptKjV3hjmobL77dw6b7mhlPCZyaglOHgEPjw38OAzMiEh43MQwFXVfoH4hzR6uHJx6t +Z5m/vCUxFkrJU6evcOr0FW69pRJnhU543Cy5f3DcpHc8Rb1DZUWFit+mAjCcEIwkLdy6gkdXcGpT +bqnTBwiF09gMjepqG+cH4rSsrSybBMAyv11pWVtJ37lJnE4Nl0srSzTaqg3uq7Fzt99Oa7WNRlf2 +/w5UqDQ5dRoqdJZXaHiMKff1mYNkhAQgFrMWRGI6maefCUp3pY4Qpfd7NnCYwPHniuzbXfdj9txK +5dX7JNAPeGxZCkVEYBZNvorx8DkZ7O5ieLCHWGSQaOQiAA1N9xBoWEfb+i1U+1YvSpkC40e4a9tL +WOZUTumGD17fwc3rfkI6LdA0BV1TcDhU/v5BeG4i85FQHZPcvvEBKiorcLgrUNAIXbxEeGSQYHcX +4+FzcrFkLDOMmR4usieTGZIJga4r6IaKNleOzIccierlNaTSY0xOjpARCUwrQtIcxVuzDMUWI9jd +tRgOC0YRkSqvTlVVcaCGB3vwBxpIWxFshpvzn53i6Ntd9B49jqF5SZkT+GrqGB7s+Vwcn4kCjzva +/bzyWn/++6v7p9oGBz6i45HHyUgXn/7tKI2Nm1h35xrGLv+LgX//hds23ouGm8GBjxbvlOGb9d7h +0FBVJZ8jhjG1tAqIfOexFfmW6SRykKSRUmHwXJD2+/fgrWpUIhMX5IfHf85tGzYgSC6aRH3rZk6+ +vqPIbl/xNU72TBTZVzVVFBO5FqSUKFLjSnQMb1WjAuCtalT27a6TSA0h5YKcn46h3oOzqtbJ13dw +16PPLV61ckTmbgNZzoYxDxaiWgVE3jxwUeaKu452f8FSA7CrtXNOLoUAsfiIzDH6NX+RJ5IjsW3L +ShQFXus8z5sHLsocmbb1W+nat43cd9hbOJKQiBIjcnb0M3k42ElzbSsPtj01954jJVJKZOba4+rT +STz5WCODQykAtj7RROfvBvJkHnho77QJ9xYNJIRAlhiRw8FORmMnOTN6nFeO7JTff2BvARnd8GWX +sZQgBLpeomodOxFix/abGLmcyjekTcGPnmnmV/v7SnJOCllyjjTXtnJm9DjrW+6g58yJAjKLUq2O +dj8vvXwWgIe/3gCK5K13snXUzP1kbiJiXjGYjgfbnlJeObJT9pw5wYY776XrUGe+baj3IHdueREz +NZZfVrrhI3jguXlVS4Xs/vHq/jYFwLAp2K6Wx6/ub1NyOXLkvZ1y3+46uW93nTzy3s4ij6UsPSJ/ +Db4h+8ZPsPHu+/j4s5Nsatta0J5OXiYZu0AyMkAycp705AiQVa34ZIZEPEMiKTDNKTdKqrWOvLdT +Brs7efQHL/Lt7b8k2N3JTDLlqFbfaC+1Ncv5MPgJK133MDNHZEYgLCt7mRbSylxzzGsSyZH41vY9 +RGL/IBLr5Zvf/WkxGSGRsrSIbGrbists5v5V24pIAEgrgzCzJISVKUkNr7khBrs7efKHnVyJn0EK +gRACy4zz+Pbf8NbL35uaXJauWjfV3jZvma8bPuwOM6+EhqMGKKPWmg1t67fy219n1/BDW36MRPDH +rj35tpwUSyFZggqF+tbN9P5+Z5F90bVWbv/Yt7tOqjiQSjbMzz5/SZm+n0gJlLi05sNQ70G+/I2f +kY4N5wXE7lrOqT/vWsJaSwikmD3x5rIvBKnoJRLhc3lJl5lsqJfkCTELDZmRuCr9RCYuSIDIxAXp +rMzuvIpa3ou8uSCFQGSu5lyJy7VkIh7vCtLJNBPhYQIrWujvO8rgwCeyv+8ogfoWohOjWKkMHu+K +hfqfh8xcLU/KQMlLy+1tIB1PY6XT1DWu4ex/3qXn45fxVtVT13QLqWQE07RwexuAT8r1vQB2d2DW ++0WpVg6BhnVMjA3i8nhIpcapbWhg9ZoWpMwwERrD4agiEr5EoGEdcGjBJOpbN3P6/V1F9iV7Qmxb +v4VgdxeT0ct4qgMYho5uaKiKhsulE524jK7X0rZ+C/D8gokM9R5k7Vd3kYpNPVjZ3QFOv79EqlXt +W63k3m31ne6+bi/oAFKxYRLj54rsJT8h5jBXms3t5KGrV3EkpMyeq1xvFKmWpmZndbt1xkKpBe/V +Y6GU9Hqzcvx5ECmIiN9nI21miEYtVjY5OXX6CmOhlFzosULzahcjoymqvAZ+n63k/otWLV+1gWlK +LEuyqsnJp71R3v3TME8/EywrMi/8oq/goCeesPBVl7ZZLlS1Cv7pd/4wJHNHb6mkwO5QcdpVnC6j +rDPEK5NW/ujNblcYC6VBgUcerr9ui6wgRzra/VRUqMRiFl6PjsetU+kuv+zweAy8Hh2XS8uT6Gj3 +L5nTs+H/5nj6Bm7gBr4g+B8P4xAJ1fJRvwAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_recursive_union.png b/web/pgadmin/misc/static/explain/img/ex_recursive_union.png new file mode 100644 index 0000000000000000000000000000000000000000..66952ea454e3703dcb08251bd2273193aacaeb28 GIT binary patch literal 1224 zcmV;(1ULJMP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005?P)t-s0001q zx!X2~!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_`zG-s;qsyLGzJqh@Q-%+2w=zwN)l?ZU(F)710W+4RoO^3l=q z)YSCg;P-*9LUN@xnY?(sz3iu{=c=sduCM9E#_!9_@xH(9!ou#w#_-nG^mC;*r_X10 zsycS7JFwk!QjHmRt30ycc6zZujKETQu|cJ%<dC*(*yYQi#9oB3MRKDxqQ_vQ%44U^ zW`?#&cB(tB+HrWUKD6U`wV8gwk2a0LQ}pr4@a(tn?6&Xfw)5}D^6bU!<+1JKu<YWm z@aVy|=X~nqo$BM9>EWC2=(Fb9mF3ry<kgbv-mJOnfA8zI>f)T}-<j^_vh3rp<kXSl z(vRufs(PNOy6%GS>9pzKn&{q{=iHa<<FM@Dt>n{?<I#@d&yDHXsC=|Tyzqqc?Z)lo zvGC}^@8-bj+^Xr?sp;6K?cuzZ%w5~PiSg>g@8!Sl;=SnCr{~qB=G3I@-MZ}IuH@B` z;?R!h*QVdchTg@6-NJ+A(V^?#t>e*;;mwQZ)TG|TgxtV^<<6ku&Wz#Air~qK=F+3x z!Ghesf!n@+<jtP$<G$?Py6fAx<<Fqx&Y$Ypwpcc+1poj50d!JMQvg8b*k%9#010qN zS#tmY07w7;07w8v$!k6U00Ih0L_t(Y$75g^1>^xnCJ=y<#A#t-W?^MxXX4=G;^tu@ zQVTC1zknc<kg$lT7_nMNw?!Q63n)p*ixQGjKvG&pR!&|)T2V<^MOB)R<&tXZ8bB?Y zTG~3g(t7#^hDOL*uzFF-*u+!=rxxs9)G#x*z@-Jd7o{w%tTk}?1-r1MjV;hGcG4gK zB^fj<EbJY?TCiG<EyOGw9i6~>aJZKN(>M(aXP_REv;f1z+0g=bbYa!PVBrGNg6c&y zE$GHsxMJD@@iq)#7-!*Tfnhl$q2L6P?j9KF2$E260x1tqFN|~qPAIs6hL^VmnqMFZ z1!u;P^700z3Ljq(fRfOJf-}iV`hlc<{R0Anf_+0m!@?tc(LxL(V^~CjT<see6&(}n z8yXj%km!r%atvE6lE7M$Q({uneADAIGPBUNWP^PHCBa&9z*=(i@(T)mi;7E1%h0u; zIvN;W<rQEpm1$Ll)xI^gb@dGhEf7DUI$Fb`yrL15lAFL`1tk&D3{C~8j<(1F>Hy^z z-{$b5#1`Myw)T!rge{O%fa+*?uJrBd&g`l4?d|KIFcHZw;8cL!(G0$mCYMfW^PM_v z!t@zPwt!Osc1JV#*3O(YyWMxr+<EgCAhbYI0d_|-_%5vPow~?(@sgzrmSKb#c1Po| z9FL>%0_={)uLY~4@dA8~9tHFV07F>Y9b_N@c>n+aC3HntbYx+4WjbSWWnpw>05UK! zFfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GK mIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTYtrHx7e literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_recursive_union.svg b/web/pgadmin/misc/static/explain/img/ex_recursive_union.svg new file mode 100644 index 0000000..353e1c7 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_recursive_union.svg @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.svg b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.svg new file mode 100644 index 0000000..6d18a73 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.svg @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAACBJREFU +aIHtwQEBAAAAgiD/r25IQAEAAAAAAAAAAMCjASdCAAFkjjE+AAAAAElFTkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_result.png b/web/pgadmin/misc/static/explain/img/ex_result.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd7b5904f9b304709ac6aab37e24dcc06d233c7 GIT binary patch literal 1320 zcmV+@1=sqCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002L z$<UU#(67SKeXh~4!_bAX(Osq0Zn@x(wb8-K&}gpOjmqed%IIXO*vQS$YP8;l)bMe> z<bu!aVX4@+#?YR;&}^sCf579B&FEmJ)}GYufxh8%tI?>y&|Rq4YRc_yz2s%c>~px_ zSfSIA(d>o8<yxZCm(uK6qSJ1{=25}wjkVEryyK13?q#joj?L+~#?YVI@LHwSTcFW` z#^!Uh-Idtykjm$8yW%;y=Uv3<cDmqo&Fy`{<dN0xWTeqv!RRu#=5@;IZp-X#u-cN- z?P09iK)mRBz~p+$>VwejipJ$*z2zga<UG3PRl(?g&g_)c?q;&xVZi4cujDnj=ViCx zTEpph#prd#=v=(zEVboDyXJq$=zz%RWX9`=(d|CD<!s68Q=QRq$?2xQ&}6XOaJJrj zx!-lf=SjZld&TESz2|<->y*ywR-w~O!0LI->S@2`Yq#KKzve-^=xegvb++DV$m?jj z<BZ7Wg3arCyWyqU@K3knEo+Lw00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0^dnQK~zY`?N#Yh+CUT!A%sLMsaGh-LM_OZl!8#apdwKLmBRyy7FwkURz=05 z^{DN?-f#qVLv*HJI{o0AVTQN6zxUqnUBR$t`S+s2aTTPh2@R$Ze@_Uhr6?^eX#=!w zkidu+dYpM2@p6b79vK~LYpmgw(Ik4&kDGzz5roD1dV(B&W5e4B`=q1wly#1~+^jML zcsL#Z*85J~R5W&<&+Tu6-BT{7A|X|P;{qx^*y6$v?}zk~X*x7LLn!g#XXoaFl0t_g zAIP46<ARx1fJ7H#9?<#k*9uEIb&ut;cg5uICm&DDQMi=5<os$BHaEGpPRal*X-K6r zalBmum3AqcgrAV>8=EE-ir5<7j^*+nDazi&@X2h!2ImzwkBpdc1Oj$;KNWK&&*v{K zHc_Fp2T>6_XL(<6MG=Sv0DC5#0-#mAvC+Nq*9v^kIK2l8vdFM%Et8knvxnJo1c6|c z&4c}KvKHW}Vy0H@L~i3sM*z8wP6~1|m|;789O!rkC-wRX3IT({=^1*&oHufd5<hTM z>Vx<$E{y1rNF{wq{1pVhD#p6C2Rn5oh%7L0oleB1N|4Fp`jMQ=#pw)z990@QuA5do z%zYPv$i2ZQ&zL%%$z6BtR(}-AOZ|1ZsiIV3#aX_aKKpI?Rtwj<S$$bw@^{6#TF;1K zr{3RVX9kpAD%Y_0MwLA*6vA-iVkfW3ieG7@w;>~pUC1Wk{1EpWn@(i<$E=y+6>NkK z&qpAySa4-uHvH^XzT03OH><a{o{ehAyMj8w$h-WttQ&NZpV96kV4My?L0ABbMGMDq z*$yScYY)=&)1fH`v<WoU-7VJ2U7}9J&`8I$z8yYm`gKnZK)LWFQpDw+wQo`T$%m=d zzQj%A4ia8s<V50kDpFI}g$%88-LN9{Um<<~F?K%Tp#n<Vv$^~qaIuPR*#L_H0A7VD z3nOkq=7|r|v-~&m2P92<JOAsn6#xJLC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@u zGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL< eG&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTXtOrt>n literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_result.svg b/web/pgadmin/misc/static/explain/img/ex_result.svg new file mode 100644 index 0000000..51954a8 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_result.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_scan.png b/web/pgadmin/misc/static/explain/img/ex_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..396dfb4feabdd85e081bf8336304129058633c5c GIT binary patch literal 1320 zcmY+CX;4!K6or#E43U(&OiX7G0Tmtd5DXYmgR&F@acWZxiv&wwL>3hgrBoq~lr@it zLJ^duAZWq5fw&ZkC=h`X77>I3W&snjFJvdI(x|^WbI&<*@7(X#z04qTpskIa4Gade zJw!T4v82aGA-}XZR*;$vgTXU`4u=peEwhE|na4_cJ>&OMPHdC^GN?%#(geLygmo&i zN3_g;wJ~hf>0VV*pQ>a+SI*I098_lwt84kXyOa8Y(V1&wnnwbI)t>@VyL>~#^s#Q` z-ez%7n>4gTN@YnI!|M1RSrS`*eOyDod9RKoioG$+D)iJTAoVnDW}2o~Kn4Y*nFci? z(4d5jN=PdLbt2HDg!CeCRtX6-W+}%-_OSp37f^A587`pV0tPWSt}w|tfRYQSEfXG~ z<pD-9I3_n5EVvjnE1@|h#C^#el^bWp;E2qi;{kdeVBi5}F*q#M8+pK-7&KX20?sR; z1r;<X(GQCC^Ad1T#TXFlOnku12j=+L1qs+M(#`ULMG4q9t)1s%*%ntpODaaswDupN zW=R4rs~Ft^&Eh0>X%f3E0nHYQkNqG4U%j7Mp2U7oF*>GZTDYnYlh_prI4U=^O{(k1 z<RH8(z;Xk43WXdD^Oa1*TAEd7Nz|V$N&2LK-gs{q?2D;G2mL}wJ?au}Fvk}SCEl-Z zn!Q~=7IE=$y}e(yGh*kDXdI~~U{jVK(F*Yxuqnx~>1&_l=Y&sWTE`Nqyi*-+eA9Md zK3zI6YurED-VlgxD2VgQq4T)o<{Uc52dBM4_ns4qT@<Dvt#*S#&6df$?z_JA^7Nd& zsc>|3T=BIfA3pq|mf@Ygu#{_8Ub(bzb>X|nwg*!@UBbMkgoVpZr*Tf=$$yMQS7cHv zJl|yI9uG%_?<;ufhl(nz-b3s9yRngm7!eBB**@c+iOV>**WUgtxir4qH!Q58sBY^X z+t^lqCrqiOuN6j!FCm^Z-Pw}A4cEdyv#acY!)jFJxKh;d#_(duq1<!#u|_inUhRb7 zZuWs4?RmPM3Lb48C_72VNCv(-0Y~+p3u~M&y#z-hvq<OPO#~HPL|HeT-JBnDa|-Q? z%<Wv4nUHu7scz!F?nr$`t8(+1oBKW|Pe5|!z>mbS2==EN8$unCzu)=|NpXJS+8k(y zsf-o0Hs=vz(jedS7h1^)Nk6Egj#I}j#|fGRi^DszZaa6=0t<S~OgC$5;PxXZf91sE zOWU(6NzTED<doV?9Qs3{X(;P@)9MkAuHxQkhHpV(D8foPn!Wy&AP<pDsLJyP%3oh& z_cAYs?`!v|IYy!w<2r@-;@--2?03|0W>xir$OP}|H5oNdm)-MvQ!!rm(9c)!#r=_M zBHea|)}|e>!%!27`lYDuS>)H4O$vGq?bkY|V%O_yDBIEKFR-P%ozXV=^u|^833oyO zaZUL45Q3B6k&=}B<!$*W;*kcVXyLiC3y+ARgakaz>j~!U7+UU*(%Cey-DHB+7FHqH zPj|}S-*ndrRToh|R<X8I9r-f-LcEN{x??i2OZ4-b(JqNaSpSxvc22t`6N*Rz>U)~O z3XiIz)B{0V)^^ow^e^-{bxVdh`d7qN(nH;q3&j)u%b;lk?cGMHsP*lX<>$Ai5W`cV zkEg^CP9(=z0_K5p$GN(DxZ>PHJa7d3E&?9!g4<2N;r5nqb@(5Um=t{~HtjQj+xH3h axJ|%$eg^tVLmyfI*dZeMV8gextp5Q0yRj$$ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_scan.svg b/web/pgadmin/misc/static/explain/img/ex_scan.svg new file mode 100644 index 0000000..a6faa4e --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_scan.svg @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +61uL/QcEs4M494QKngAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_seek.png b/web/pgadmin/misc/static/explain/img/ex_seek.png new file mode 100644 index 0000000000000000000000000000000000000000..130fbd8f53ff5c2c757c8173eb62a1b604555f34 GIT binary patch literal 1326 zcmV+}1=0G6P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=yH~!hN)yyjTym@HuUhw@a(tm>$dan$M5O1^6ka$=CkqY#O&j+ zp~PP6<(}%}obT$j>EN30=(FhFndjV>?d7rN*p%$xt?c5j<kgbw;jZi7t?lNr@aV$t z=D^3Qb@1lE>fEaD<G$n4kK)jc>Dj2{(~#oMjN#0S=-8+2;k;g#B*DnK#F|j0%w%+@ zIG(kKuGw+%>WA&)VD95x^XP-`;92wMfbif}@ZVJQ=6#RAQ?cH30002z+A8STDCyWG z>eeFb)Es@XL#xzmv*LH^)gSEB81mgwaGgbAl`r+=dg#}t=hUR^+_~n_qTtDi-^YgD z#D(V5q}{`W+`xk0$cWs(faK1gsoHLy(PX^vg!0`^^V>}K<977gNQ<j%pw(yY&=l^^ z5bw?o^V&-A%?rQBx1!f+zBxuV00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0_90WK~zY`?b6v(+E5e+U>k6&Tea1i1BihN$R<*($RcX1MKFRGK$JxVf+$KW zhy}F%>%F-wiB95-Go4N!ybt#&-#z)Ab9#DS&%Zx!2<}MUVuX;%<?>#luYX`*kQjU` zlMN9=eZ#{e#K`E_*gHa$$j8UW<wXC)#Ke2z!{p?ojOaytm>8X!l8q66sme$E&ysih zt7&qYC!kO&l?v`wDPTseR?osLMNt~iXti1mw7()hkpiNeo10UDQm51DL2WP?=7BPr zOlHtpEEel?M1_c&BSs1+lgXro1&hV@3{im|lX;^N5wpo;(ZZt5X0wYEg;J%O;ZuCZ zDHa^yu-ffQqT~y3NAec0qSvcYm3fLnRm^78CC#GM>VRdZ)43x4V<?4zPhsh%aJt-X zk2q25T8%Zf8@mWro6YM4r`x?MMbIodjcv`s?sd5kS@roO$Sh8w!6_Vq6e}Lj+B#1* zzIONK8}5wc-65M>-;p8xoPq5?Ah6xNgTWoxp=o*tc0-}?Ubo6-WNU*YN&h}F5MZKA z00PlyGyuU^EFJ{<;NXCUP$H2C^W-qHdF1!+CzB*1Q6`E>EC|7PJWeB$N`)YtNT)MA zA&*Z`6(sm7u~>_s_vus$y&p~s$r0`tnG|LTK25Qg$z)ESkQa5#FPw|RYPB!JQhOF_ z*>zaY<#Kt*vn-njQ6gLqkFQY3Lhh_sJO}ooRAReiUr6j;FJ6yTv>w?);W7ugV)23n zwp6+*OAwdK?L_bUd~1-sJUh$5dGP|1D*;IgiByVwxm@mMIr;J89XtMch<EH7&xM=C zF6@TGtyxq~;j~(<-oQ<*R=ep`xsCif<aX?uGe9#bCe)sFre3dCpxS6Q@1S;ne_!j6 z-?x#6<TXBM$LJK(U5`q=-l)P|v)QaYCdl9&YgGv`2__7gbiIy9qk#$c@nh0%Tq{c_ zMWvPEu9M<XmiBo`$6n9>cm4nf0rwvzb1L2d001R)MObuXVRU6WV{&C-bY%cCFflMK zF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGP kFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f_kQ{fB*mh literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_seek.svg b/web/pgadmin/misc/static/explain/img/ex_seek.svg new file mode 100644 index 0000000..22510c1 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_seek.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_setop.png b/web/pgadmin/misc/static/explain/img/ex_setop.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a9b1983b5b47c96ae910e73ab4260ae9c28b73 GIT binary patch literal 1143 zcmV--1c>{IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002E zxzL`V(1?rCc6!ljZ_&-ct;w>B#-wM%nNGrzJd>5te}mbYo#C;w>b<`0$jI=)!tS)S z>Yk$FfrZ(}s&>qySJ}LM<k6by-Kg#6v*XQ`qNLELspq@A?YOz?x47%Bu<78)j_l>D z>*J&8;hW6M%aoVjwzuoBvgxw3>bkq^zQOKonbT;Cw%F6E=-!y;+?VRzrRLP5*SC1B zujqQE*JQ2NWs|?=+Lq|snys$rs;uaQsoGkq)?dWwX2$7un78KHmFC!#<=2zt){@q> zb)U22NtVh}z2-Hy=1RThb;#&boz14Or{vX=<kXSo)|jNH<fy9WTeRLOv*bFs<#o5* zUyi-x(~#rRkKMwEAh6_t&FbUOj<dAt7_H;t&Wz#Ai>j^WVVTb!u;hfp;!=vh;meBO z#*ekO>Wt0lK!(EL%8BLApgM`e53A#l)9m2Mh~LPG-^YjE#f9R_n%=~P-olRE!h_qr zgxtV_;K!5Guy4}DpWelaCqTqQ00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0xn5JK~zY`?bK^i+CUTrVD7hwTp9u~3K&4efQ155Dpjm4f~c)k&`L{%-n1>) z8Vm%m{&hD%k|mfKr!(y*&NpUw=DfQ(dlZUEP3k|EQl-{twHmcbIry#98;mBC(V*AK z0c6TNZLwNy_D3iJkj{ZQUHHrlPB<~gy=WGlv$#E8ug7AuTIbPOJx2O`et#ek@cVEQ z(~p4#WO2zm9bC3Ac_=qPq43IMANT)2Boc{6p2Xsg1qngSR4_5mlTc_inS9EFXf&02 zhC3aSREyMFdQBwH*EcfBO%4E&da?EL)fS!|$)-f@i8MsEbNQXZ?%w{O1t(s=IdEa{ z9UyO)4`C8M+9{SY$0rd1ygNNTC_~YdQ=T+TwsVE|#Zvym-aY_BQK?j7P#cx`;~Y#@ z*NbPxQepRaGbMm(wdRV8r%``OjF8VqUpSKa`fZqr1GRJF!XOaM_w)$K<<I)$$4{|E z?Yv%V7zLtrAHsyXEd1ig#_vn9Mg5AVV<tJ`7D*pe`=HruLPQdb$`$xve5NY^u4%^j zfaCL-0Jv_EZNmdDS!~f_Sppgv`A=CNwrBy-V&I993`~e0m^z<{1x0q?S(Y2i<{%R% zy5-);Sjr4PEwt!%S>{IaFeOjS2A<dne{2A{WhN_mVq*{45?=X3(8Ek!_M&$)_K+p( zBEhYTPJ<wC!A;%vn9e=xqQ8_-b8vJi#oJ7y!L+k7OG)t;t8Y@1`X_Y<dEniZp!V7a z0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFU zC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ov JPDHLkV1j^qN`L?W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_setop.svg b/web/pgadmin/misc/static/explain/img/ex_setop.svg new file mode 100644 index 0000000..8c31bea --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_setop.svg @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +YII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_sort.png b/web/pgadmin/misc/static/explain/img/ex_sort.png new file mode 100644 index 0000000000000000000000000000000000000000..1d46fd34beee098f997529bf0b7714c52232a2df GIT binary patch literal 1157 zcmY+Ce>l?#9LKkGD0JGb!<|bOQ+Me`PIBs@X131ubm*x$mvXaab;*yACb5J^<yUCU z=?G6fnfz!u<i}*hkYy7xW3|nXjiOR_@wspHSATpy@8|t_KCjR7c|Ol4eIL!oZ1p#* zQ7Dudg-rBA)cHdg8z6b}L>w1|LZ92`8{m!DQ{|nmX`=An**#5DzO7UKZPUMtXP6Il z5fWW|pN=clXUJv+$_1mFs&#^Aj(62w4Qg7mCQzhhh$nO8bCLPQz+!<`3u9yCLG%bb z?15U4$&kq)mBQ#~6BITAuO9LqLIsSB)IkpP_6i{rRI10&2s?LDwdh7Z8fJ@NCJm;! zFd4t3ITfD?Q+k-tfKm+#6{x2Ho*jVkUqDF&&9OlR$ex0982Sc5B7<QifWi&bjP3!r zaEsx0$?8cB`nK#iITTstVily{c^X+e5er>i<q%g4k%ho6fRJ1W5&*YE99$-0RE<W} zX*u<}b08K&QxnwJgHU)0{BOZo5Q%sYYAS}-7f?P0MUzmdg?qD*qJqS6;3y$x4DvM) zseqCx$W=qd3>dXTM?bXpLR$}rBv8e3)XBr99y8x4qpF)h&;TP34lIsGOB-m{TFz%8 zmqJJT(fm=Knjt1)R-Gi%qYx#33{uyzT`1HF4+_yMfZVAcm^py)vTU8m)18%`sKnhj z*<uksYUi1eVOfJKPs>_|AHuUzvW>}&>XtFnD#12=5jSD-l}O2Xy6AEAsv_w~<-a~= zR<a9*e9KC+;FgGmLH*CMbBgT*1FGqRFG(blkIk<5_s=(bzrrV0ONLT{JvvNXj&wR) z>7XZDI#BoKl9GL|_MWroq;CqTDQRU3U&c7L*{b^OT#I7a=4*Z|__`WB7ft(h<#lmL zwVU<juuHW=)EJqm7n3feC-+#%HCxw=uD|m{yYOyl`E(|KL();vVdHgcQY}`jeA$Kz zd^GU|aTDfZM~Hc9Sy{U?g_H0ClY?C)4vFx^B<8H|$3?8%P+fzuPdEAthoRteGj^qv zp2y-%Cb5#6EEi(d{<;x1@Ul9Xj(^`H-CwfeY>d+eFuzNvy3((g8#?Rm4)+uXRZ{0S zek&Lj2&|vqTX>h8z4p+Yu5=*Wb*%X-%fX;6ZCeB97F{VJdvHeYIL!geO(qzY#fd~4 zgP|L%u1gYzNTmVY-#^*ix*}V#)w7h0IfJh~v<cg-uAtgBZSQdJ-+WSx^D$TOOB4TV z&ougHZ<*gtEH4SK60NlsIlMIuW@DxNaj!)u>tp7<>2HN#d3gq@q^0Jug@L!_)33u3 zSD40j=<&?;yenlDmRu9KMFjKSyr<uxY0vOCm{D>(4e9y6VRvwCmgKfwx9qwK@bjUR zis9q0OCHVF-XIovFSc|R*2(*Lx0j!tMXN^#U$e&f2a$)ekM=$o%{USr>i$P$C?Y6l zf)l~f$=Q+M6yQv7ciHCd;_?IGCwBtDjc339GvLo~Mi}$-CxEcyBk-Zyo#6Tj=q}h_ PfdD9qH;q`i`*8CAb@5|F literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_sort.svg b/web/pgadmin/misc/static/explain/img/ex_sort.svg new file mode 100644 index 0000000..0b11003 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_sort.svg @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABUlJREFU +aIHtmFtsFGUUx3/TvXXb7lISaltoJEUTUwo8aB8kQDRBkYSUEFCJxCAoSPRBQ4yJaWKMMWmiBN7U +VJsYjIo1Yox4a4UHAga5iBGBhoZws1bKym730u515vNhdndm25nZ2e0SY7L/ZHK+25xz/t/lfGcG +qqiiiiqq+A8gGTW++tkJcfRGyraSh+52s2fLckNdVqikHadR49EbKZY/upTzE2m8DvDUSNQ5JLwO +iXoHeB3gdUjUOiQW1bt4e+BsqRwqbseQCMD5iTTHA0n8LnUCWjw1AMxzg88p0eCQqHNKeKSSF+KO +2DElsqTRBVB0phbUmaqwhUrZMexd6b/G8Z/UctSGMyv91zhVkvuVt2NIZO+5E/DGGojHi2v3euHN +A+yz4ch0XHx4G590nCBCoOhYP028NLzNtL/GtCceh6kpmJpCWrRopoxG1WdysgwKGiIECDNe8HRJ +3flyiDFuc4Mgo5Z6St/gslxYV5SSVdiBgoxCJl8uBvtEphMAyGRsv24XOacVMrrybIh4vfmiuHIF +FAVx+bJaHxnRxtXWluNvHn6aCuoZkpwRh8iQLGivY46lHsPgLFatEnR22vfmwgWkY8dKvlC6/5ZE +OmR/vGsuHGoV9m/2w1uP88im7SDfUhtEWutUtEimKGlqajs4fLAPjtl3KIelnyu8vBUS2clXRGG/ +ottRtbXw7qdwyHjuLaKWfAup6TVI/IZ01+uQPK/KxO9ILb0QP4Vj/h5I/Fo6Ax0SSZiMQ3QSJqeg +fYFEJKbKcAzCMQhGIFYkOJoT0a8CgBzLtuemb1q9TChCC3yyQQA0ajNC8ahlRqDC0DucC5CyAkLM +7DeCORHnAsTNHlXJ2GJgCjF2H4gk4q8lAIg/F4JrYVEnewd2iDOj39HVto6ezf0Fm9ztAsWj1S9d +FQUyR8BbJDganpzhbyQxOl7UvzzamqFjvXE0Adi4t1U89dgmDgweLCCzdqcQ9y+2b+fsRfjxQ+M0 +2HBFdt8L73QPEeA6MPOWzT0yMi3cw+7hJwBt5g0Nedxsf3wrH335Mb0DO0TP5n7pB8cLsKkHIhF1 +0PRLN3fhZjIwdy5c2mcSsyy2VoDrjHOZNOoXXJoEO6T36BcvkiZBJtsuo33hnRn9jg0PrsHhVlNz +d3Y/uGo9OFxOnG4Xu57ZRd/+Ps1QJALhMADSihWII0eQVq/W5OCgrQzClIiCXEAihziRfDlFnAxa +dOtqW8fXvxivyM4tz1HjctK3v4+utnV8Rb/aIcvGjupXwwYsiGTyBGTSM/KdFPFsn7Yi0w9yDhv3 +tgo9iRnj9M6aEShCyJTIHJp1zsrIpDgo3lJ1ZldBJkUT7ZYGQF0pUxJeLzQ2AiBOnpwpcwQaGixt +GM5gJXMgK1QypzNsbPhZiG87Yczg0k7o8iFFwHwPPDkMsRWl/4WopB3TFGUsCVeTsKVZystLcXi2 +ReJKVo7E4VrCTIM9VMqOea6lQyqXC2VnKZWVGWE8vlzMxo4pkYxNxfIsyVTKjukZ+aIDbqYKvxFS +Bopb3bBtpPwzUik7huE3LdSDZRfpMlelknYMibxyGp5eDxO6v2bK9J8nQk2xG/0w8D302vcnj4EL +y+juXksoZP5pIGfzL5/Px9DQEBtMxpmekYkoBILas/IBifHbmgwE4Z8QTETMNNhDKBRjXuf7BINB +QxkOh2le9gHRqPW/SFMi+hW4A399Ko6i4ff/QAIscq1GvxZJhICjp9VKTurHzQb19fWMn3sewFL6 +fD5LPYZEzl4szZlSx+fQ3t7O4OBgSePhj/KMVVFFFVVUUYUF/gURB7EPhSihDgAAAABJRU5ErkJg +gg== +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_subplan.png b/web/pgadmin/misc/static/explain/img/ex_subplan.png new file mode 100644 index 0000000000000000000000000000000000000000..e13d7794e91fc0842702b0b34c1a9b61607dcf92 GIT binary patch literal 1283 zcmV+e1^oJnP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002O z!_bzQ(SL){ba>NdYtf>m<hHo#y}#_l#qYwz?#9UP$jI=?%J9p~@y*Wi&(QMG(el&N z^Viq)tgh&<vFNF*=D4}*zQ66j!R@lN>5`V;n496cyz8c@(AnDc$Hlj+rEHy)MVE~( zje!}GmC?n;b=BCB+u@bv?y2JJpyBGA(b0>*y>Y_8Zq(O`&Cz|**oW5HjmgV)&CP_q zyl}CsSnBe)wXlcC#=6+uj;W$#*yDlM;eY7uxXQ|X(bI*zwrqx}WKxY8b*9HQh{34O zXl={vL%r!uzvx%P>V?$sl-Tfk&g_TN?ycYR5Ub*n)$gj(YI2sLtk-VAk2du2$?)v9 z@9DJj?Z)lovFzcl@ae+p;+*H(mgLov>)x!v$huvZB(B<V=--*+(T?ies-Crnc&$CS z>3-?jshY`Moz7yq?t<^;!0Fhh?&7_NyG?JLL&vIhi>qwE$G7O#rsmV5>)g5C#f9C% zgW=4J+`xh5&Y;`Af8@=c4PV1400001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0=h{=K~zY`&6Md=+CUh_IT8h`QXz`eqXw2kLy;n)g4XJmdbG8avTB3Kp(v<$ z)p}e1_3p-?5Zu7nnNFV%o0)f?-@M1}Mx*)X((3dKs}!TxX;p}pR)f)GG8$jBwRd!w z%`ZDUEmpIMqcggeuI?_I0%_~9**P5z(YJQL>Qz?8^x17DJq=;{x!wU~4cdV|%WIZ~ zu$^Xx5QDtK35c8yeo&)jELJMwVp*3&xINyX;bB4W`rcrMwbBt;yniI{)+-1?FfbY# z<5dwki^CHb36sj4;gCDzP(xg7TRUOE_;`3?5(g$H!Vxb}L0qhf<BXVz0ua3qO*$hH zHH5VoIL=<X3)B(ZiOt5=WWh)fsJ71<dhlKp3=LHn5NrmCg5jxYL1vmmz_>6q?R^LC z+aGBz3y6${r7U>JZlAM>UNjEhXh=TF8Nd2bRuFzH;GTIO2?j%Mzk8N%fEdW$AV22w zL@?s<g=QOEOV-}=<mI>0-wW-D+06_Mp*`e&BlRIa<9G3lpVBjaeSfJrI7i?75F?V; zhba6A>5ka^!s61W*yk_H%U@$pB6W_~LOdQ{ip?)B&3~&x5><%OLCKO($?{#QQC=UB z<Ren&Kr5@OYb)r7D5loYlSrKdt)|oIH6(6iGFem^Z!W)?&s9dPbVz|M5s8^hVH*(_ zo>gwAm@Mw(G_XV%g#!oHwzf7zl+6?hyND182=m3g{rzGd!crMCwGM*d8pU;Vu)TYD zgz$MJ63OJ|-to!teyLO{m&;J$!1{@Z<P~R0Bq4++r@u~5@V88|)H+C(^;9Z*fR4`2 z&M%~1s%8btQZKa*97stu9$sEvoj**h=5i_>8k8**uFuf<<<-sY<GEC;&VjbCuSwwQ z=Jy>1Q997kA*u1=_V(_Af+!tz^Qco}$N!-}nbr1E9_U2o0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1oA>oooOA literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_subplan.svg b/web/pgadmin/misc/static/explain/img/ex_subplan.svg new file mode 100644 index 0000000..6ac82f9 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_subplan.svg @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_tid_scan.png b/web/pgadmin/misc/static/explain/img/ex_tid_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6063a1af031c626802911fdca598983aff7d52 GIT binary patch literal 1074 zcmV-21kL-2P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002d z;PI2T-@Mf8{{H{L*6o?Q;ibal>hbyT^!nN5^vBrl+3WSI#^#K%-OAhV<Lvi^t=n~> z)~3be%jEIR<?+4P?Qx#e)#LN7$>)Ek+0f?l*6Q@d;qbxV@5$rvYnjrc!{ox+?t7-# zwb1FX%;=%P<Hg|a#oq4t`u(HD<awmm>Ezqh$F9h;kiMjKx|(3PkxRstJB*5mfq{XC zhlh@ij+T~|prD|vtgO7eyv@zc+}zyo@bKZ`;laPVtDlO=oI}p1PuR6w-oa?$%4zD; zYVFo~;L^J5>E!0-=GocV($dn%$jHFJz_hfqs;a7)nVF-bqn?|W>)wU&>3;X;Y4PG! z_2EYK-Z;soXy4!8*4Eb0(9p`t%EiUS?d|R1)xgxbiOHZ?)2mYZ=33Can9k15#>U3O z!^66|x{;BQ>gwv<&a=<QxxT)>xVX5tx3}Kg*UYkn%e$bxy}jh*<eZ$G=;-L1o13t( zu%DlwudlDArKN?1g_M+(;^{T(00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0qIFZK~zY`?UY$l+E5sVm1q!Z0s&d05EXH$OJzw&f>9JvV-~<xtzpr&mJ)3# zt^4}dJ;CwH5a3Q{crP>OnfJ;0@};Mzn|G656V%rsV(N#@1DyaC>j%>yg4)_VZtpi^ z4$R~na=AT7>*IZ1AL@sFZhUwc9|;5piB`Y>L|~&3j^krablejP42`#Fv4k9O$mI$; zF%N;*>=WT2Y&Irr9@rh6L@)yJTD0r+VpD$OYqp`G5qH=Twobo1f&7qh2|N*)`RMCt z5>^5=+dBb3rrVuclg!S|FML{Dj6`FxSe&F1G{YvB49;`QE2-7B^m-<<5!u}0xots| z<ZO=2OPoHy%R7<P^ye?Td;4GaGY3ktP$(AJk|>G{P073tp-|<+t)p+>BR|ra<Kx}6 zp9P^(`c;(}RaK?3e4@NYvh3lhmf7D8Y$NrD70Xgh{acr1xh^r;=Ey0}bN}Z4ADn5# z`7_Z35rLQn@fV!3T@cu3sYXRZOw?(q(U+=l1rYG!LIqTS4wb1%)v`)c*EjlN#riFI zORLpVMG%CdCdSn7?sHM{I%^=7WY6#Nxs&Jv80AAeN<QWi_cvX!_a&yZ5Yzei!HOA( z>8=<EC*^g;nl5r9OG%cY6BHS5^LNqB+sG4UmhG=%BJ%?P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$g8msoqyPW_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_tid_scan.svg b/web/pgadmin/misc/static/explain/img/ex_tid_scan.svg new file mode 100644 index 0000000..b11c048 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_tid_scan.svg @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_unique.png b/web/pgadmin/misc/static/explain/img/ex_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..cb70480be8a4f49369d9a974ce9461284d1a4654 GIT binary patch literal 1238 zcmV;{1S$K8P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002Z z#KgUKcgI3Ps~Q@~u&}o&Ddc5l(9X`ss&&DSHnvqK%tl7dN=mayB!;PEQjHmZrCYPX zru6a2@a(tm>b0~uF5<tRp~YT>vPSFWp6cS9>EWB(wt%)SEA8a5a-%iq-I&LARP5lb z-DPF(<-exPW%BF9vLz+pz?JIUs&=Y7>DZ_2+_~o1l-8qo)LdNR&yAk7hpyUjc&<L= z)RExHh~LMC=Fy_RTtmV?KjF-Z=+~yT<a*t~g5%7duOT6OvqIz1kK4U}xG^!fML3PY zQ|HvA<j$bIJ3G^6X1VKs(35S+RaLw1gT_uymdstaH8rt4A-G~H%wuG_M@zb8Ws;TA zW^2)iL34~eXwA;?y}#|h!R^Ar?#0IN$jR`_%<--<Hq^DqyuItEspqP!=dQ2mv9s#7 zx9hx}zpN}W)z$R0W_!S=%C9#);NbVg#O%qp*3r@OwTrE~yX?Nd?W<8{vvZEQtk|zV zN|H5LgGPX=ey69T;D1YtlFETR00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*y&TK~zY`&6N9F(oh)3hs+U!xs^aDm&vUZae{%Mz>t6d6NpNgVwgoYFIh(3 zy7;emwsT-WPoD8Z&*S?eXP>?A`{nFI5QC)~(-9-qn4TPw8K(^79c_;qX;>yRGhrkM zmgDZ;!yxpe#VVK0K;5Sag0tJFa13pkb~v0)7iDnswA^I|Fc`!t6CSVG?Df&|5A2Mc z!yy3hc-(%<1rabC4w>YwJny3XHeUcC4=@N!Y=Y67XxiA1bfc8ZIN0SO&+|UgKRXvh zUD&C47Dj2YfB}5L&;mV(@PZ&Ly2G|eBm_^E<{w2_CCX`sM~Fq1<B1`}C&Xea%&Iq; zOraAtn&uS5sSu)=8Af8U2<cyQC6^Jh6isJYB}$L*I2jkk+%OUd1{d?;LMoL)BePGk zEL;+-QB0IFnW0^bN?v7?8Vr}lB^C%K$n~|kVljbU#y!RTm7(NDzETiDp<uWw4oSsV zYGtpCl;9o9;t`QtCtYGLmn$hZIa_^(yU7b1^-3X8DwULAxGEqp-;0rcUaP<81*7Gw zBy{A<kv%cHxiuOAn5}W8+b#20LxQz!W_B9d5|f&{uUdPr_um+(w~{uGN$q#<KYaXj zKp75?ByAo;$g$acEF)SxhLA%)^%){~kHK9IDF4aP7lhzE1{2$1^xKlu=tsIy%GLP0 z%U9sB({2~!v2K*jZ{34|T{`aYNox=7f;@(n{C?Iu7(mXM)eH3mdJKaAk6o%=pvP`N zn!Bw|K76H)j6C-5UF2YX)XG2AV35adO6;r+Ja($S4C^s4@~?d5s&8bh#{hC(D_^Jx z-eXexH}KeH7t!J|X}^=NZ1#fD;;{zEtA5=J<`#PF|I{BM#JXLtE~^v(001R)MObuX zVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn= zI&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f(A@n A@Bjb+ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unique.svg b/web/pgadmin/misc/static/explain/img/ex_unique.svg new file mode 100644 index 0000000..8e43bba --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_unique.svg @@ -0,0 +1,69 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAABz9JREFU +aIHtmH1MW+cVxn/X1zYBl68EgsE2SWgWKRnkQ0VZutKlidapm9u12yQiTftnCdO0TZ2mdRNrpva/ +MVVs05Z1qaalqVStm2ikpAtlaas1gYaGkEBpAoQlGYEUA+HTGAIY+9777g/DTQy+1ySQxZrySFeW +7/ue95zH95xH1w8sAc319eLD8nLRXF8vlnLOcsCylOCx6mpSzp/nWmkp95vMXRNpfOcdETp+HM/D +6wGQU1KWrai7gdVooeHtn4tQb51h4Mhb5az2rGGg18eKLSlM/+fv+lpFVZlo8tUAUOTcTbHbyzM7 +vy0tY90LYEgk1FvHI3v/iBIeRWjagvWPq17EWbSW1vrTbDn4S7o+fU1fa/LV8OyOJwHwjdygyVdD +dd3fxL0kY0gEQAmPEp7pR6gRIkJExmC8vRc5EI7cs1lwfG4lfHorrtjt5R9na1i72s2Wgo34iJC5 +lzCdEaFpC0gIRWW4to1sj4cb17vJfGojQlGi4vbvOSQdfaFfyrJv4cK1DtyrnLTeOHmPKEQQd9iF +EJFLURGKCoD/vQ4y16xhqKeHrCcKDWP37zkkdQ/6lq9aE5i2li0pCy2kYLFb0UKRX330YgtSOPKU +1HQbmZuKkG0rTZPYkpKWqVxjGBKxu3bSfPj5BffHPxglb90GBjs7sXhmaD/2ir4fzt1R8njKGKum +R0srYwqGqWpt+87vCM+M6PeEonCq8nkyvC7aa2vZ/PJPSHFnY0vO5uLb5THPKXZ76eq7znpPARVV +XrF/zyHp9hxzyqjn0DT96QtFQZttadm6kvbqlwxJmrZWeGaEmZs9+vex8z4cWZlMT09jWZWMJT1I +cKJHn51YcD70MP+e7GDH1u2ca2umoqosisycMgIIVUMLK5FLUSOfoTBC00hKCZuVGke1ZtVIU1Q0 +RWXg/fPkuNcw2tPDqi9tQKhq5BLGbyd7vS9KGWIj59qaeXx7iaEM64XPI6EGQ2ghBTWsxIxbFJG5 +BABaWGH4ZAcZLhcjn32mq9WcPBvhcM2vxbjtCo9vL+FMy1mK3d6odaFpevtoYQV1JowanJm9QlE1 +mMG0tWTbSuwrIocMt3xCak4O09PTJK/PIXXdhluH2FYZnnHjZifZzmzOtJzFMVXA7W0FIEvpWGUF +IRQ0oSKjoskqwqahJWn6W0VyhuvuiNhdO6MGePyDUfJyNzDQ1YWW5+fye79fsD+WajX5atj32Hd5 +veoNjr5wUpof0/LXn5oWuJgcpkRCvXVsLn2F8PQQymSQjyt/gf1pN+MdHWz71c9IykoHIq1ld+SY +K0qSLeZ9Iyk1hrG8m7ZWaOIGwZs9+Bt6SM3JYcrvJ3l9Dqo0wtTIiFloFCxW0zTLAtMMQgi0sIK/ +8RJpHg83+/pIf8y9YJ9mMPAVVWViMuXa8lQaB/FVKxRRq1Snk9GuLl2t5iQ5lqJUVJWJb/42V0ym +XOOJkl1c7bxCkXP38ld/G0yfiNW2iomLDaS6XEz5/aR+Ph+HqyDqCQhNY0VablRck6+GH+z9IQBX +O68wcFmbld23lp/BXK1GC3bXTtqrX2Ls6BDZuUX4u7uhaJKrJ1813D83jMVuL68dPgj87/4hmqK5 +vl4cycsTTfvKxJG8vIRwS4xgOiPK8DBJDgejvn7SvV4eKSm5f79qHJgS+cJzz0k5lZWQn0e617tg +PZF8rSXhw/Jy0bB7d0K03f+/r3XgTxdE2yXjwFN/eJMvezwM9Pq4XvB1+htkfS2hfK22S/D9fWsZ +CyhYLCBLErLVgiyDLEv0fO80zuKttNaf5qnfvMyBf96KTThfy+8PMTSsIMtglS3IVgmbVcLe10Zy +cAKASTkZaW0h0KnHJZyvZYRg4790X2vFF7+6YD0hfa1YCJ45oftaD+161nBfwvhamZl2JIslakam +O1qQ1GkAgmlZ5G/ehMMhmx1zf32twk3w59e7F9zfcKGKXevWMdjZyeWU7Zw42Knvv1PEU8ZYNf34 +R1vuzNeKqVoWjb5jx8nwemmvrWXXgVd5Jj8fh0OmovJKzHPMfK14ymixgFWWsFotpjkgzoz4/SEG +B0MMDYUYHgkz1lCn+1rqSiczDidjAYXJSXNfKxCcZMfW7YzbrlBRVRb1BjA/x/BIiNHRMH5/mEBA +IRBQ4uaIS2Q+ps68r/ta1pJvLCpmsb7WUnFnqtX4ru5r2R/92qJC4vlay4VFqZZNlphoPIU862uR +v5Gsgtyo/jVCPF8rljIazchdEZmvWoXnjlDs8TDQ1UWb40lOzFM0I9Uy87WMlNGsJiPEVa1AQEHT +NPzHPiJ129MMtLbylYOlWHNci1YUI1/LSErvBot712qvJW3W1yJ/IwHraqwBBascaYV4uO++1hyk +1lO6r2Xd8a1FH55QvhbhGWh8V/e1FqNWCedrpafbmfnkI+TZtkov2kaaxxlXURLK1yrcBH95o1tX +K393Nw2rS+l/87rh/jk88LWWgAe+1gPcI/wXz9b1PT24TmcAAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_unknown.png b/web/pgadmin/misc/static/explain/img/ex_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d54f5c7b253978b96993ea260828a144395095 GIT binary patch literal 1088 zcmV-G1i$-<P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-s00025 z!qAqu(2ljybgR*YvC*c#(8$fuxW>>^ozY{g+H$$zaJ}Pq#prd!=Xk~Eea7c~!sL0n z;BT|sS)tRx%FtS*)o#A!TgB^2zUV@{=s>&YKf2~ayXQu|=uW=pS;FaL#_4Uz>V?ql zgTmx#uG*ix&}^sCZn)r0!09iw<{+@-AFtyivE(VU<S(@3G`8hBxaB~(<wd*ZOTFe$ zzUOPl=~<%FSE18r!{{2W;}xvqRlw(3!RL9*>ypmuTB6fvyyGgg<`JvnU&H8?(CcKb z+6}7WW5noy&+LiA<Yc7LR>0^9sp2xV<VL*aXU6Do$?BHZ?`E*vFt_Gl#_Mpx=3d3> zQNZYfzTthY(P6#i1*qX$pwV}|;(pHSdCBU($<S58=^e1-60GB4s@Sl@&}p>ZUZ&P@ z%j|o{>5S9ub++Dj%<5;W*ml6=ipuD1!|15M&|t;sdd}^2y5K>(=xE66YQW}z$LM~@ z=wip~XUObp%Itj4?KV3{{{R300d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U z00H_*L_t(Y$L-VoSJF@z2k>#Zm$&&66HySyHefJJgw$z(fRdI186mP%OejOc)GU0- z>Thp&cTUGnWA_LBjqi^;_jC5#=Xowg_45ER0W(yCfW=C5-iGWBdSGy9_=%GlaUqi- z7)9=}agTSxH_7@rUI+w3XtcKw!x1Su^>jKm6Hh#wotx+6KyX3qS=8e5Xfl=jOVUex zCY$SJ(DF(?f1kYIGpjlM+Q3>O|MFk*N?zYUx};D{l{E6&w>hhkH|4iEy=IG*tr8}& ziR$)Hxu#$u2i^f4va_4qyCc)=fD6L<KCfW%UbnKkRKg@awqsLAR5&PNlF7pVi-x=T zA@#A_G0)+r?gu!`8IsoWZc$>r-g5o!YDdRuOx8EdI)ya=f(84cqtfc00Its*zP`{t zvGm*-tI5)xw)yaY^JDU5HB1@DiXyUq6VF9xpNhu9hUnU)HhsCxm`TK0GodYv9AJ>K zpwO8V$2+zpw@(TFp)QUR#cP=s&KF1o75*B>n>;TB;RT6Mw;+beHz%@@2+C4n@q3xe zxX1(rB0fx-PLf_>Qk9e@SL44kfRHrYjx{x*Q0S;ZNGK6#A=nd5v?4T3cRC&Bgw()6 z&n4?oZ*z4HNy+sL?wE4ZCuHQu?RfR}=da`6SyFNV?OMnlOFxg0KS=w20#>Z+^Z)<= zC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!q zSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMn GLSTY1nJ@bQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unknown.svg b/web/pgadmin/misc/static/explain/img/ex_unknown.svg new file mode 100644 index 0000000..09268af --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_unknown.svg @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_update.png b/web/pgadmin/misc/static/explain/img/ex_update.png new file mode 100644 index 0000000000000000000000000000000000000000..a45c53f83a0593704855bb8488871e8e8c9be701 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003#P)t-s00016 zTU$1W!3nA2a+aZzl9IuXHZry4b*9Hbyy(lKSW3X@*Qid%s&!q&>iw+&W5()h$LMIt z>~72Kb<OPByMEiff7`u@<Gpj-zJT1nfd9QPd(rRQ!GeU*?%l(Kgwyce#Dw0(h2F-7 zjMVPm$A{m@h>_Lq;K_;M%!-%U@#D*$;?9iY%%0@Up5oAr<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp{Fb>D#L7+PCQ5nd;rD?A*BN;F{~+tnA&o>));H-n#7It?J{P?cclX;jZoAyXxef z?BcKO;k@kQu<hls@8rJi=CbbQv+w1=@aDkp=(F$XweaY|@ae+v?6&di#PaRM^X<m- z@W|M;qjdlP00DGTPE!Ct=GbNc000SaNLh0L01FcU01FcV0GgZ_0007=Nkl<ZNXPAy z-B#LA5QQ<eL#ah;5tS;UMbwA_5<v)|fIxsm0YgCuG)2mv@BaclIp+XDLzfq>)m}Ik z`zl|u_nwKx@;3iqJ}~+$R5OHe*le~9W_M+Eb)VV);&7ZYr@MQ57tF=s@$q-Y6tOKY zFWZ<Eq^rzltJUgYHW0qY9ImfBj+s~b$~)|Np_(D^I2a5bC)(@vMljMeZ3shERr^4m z0k9j9!To)$N40l*d;0*Il+U+8O{EeF5Mun>Zl6PH7^x9N(m>1S^C~n`i3##!Jnm*; zhV*LqVXP05gphXrI;BEA5sz0XlFizcG0d`H|I-vdaf)Ui`bxFjrCB!Z-`K&F`2_lG zW8HeL^u3$4uQLXA^nuZXrj20OZmUD+*A=A;U0IeplNZl1u(P(dwqr=q)KgrQK@JCl z;>^E+p@=3)q}Ws)l=#)94014dCK_tO3=TIzaIq>bwt5*3%TPQ!V{>4cXY2w@vpi4H z5p%f~7?%#4`cmO#jZGLtp*Uy@&3d0|w^~NK=oCe<1FcLZ-GKRfgiQARl7;%8Pr;%T znUf=*08efhU<o1hL;@WKQ8^qA7C~fLHUsG+pZ6(3LA}y4RZ?t@Jvm83((Co|<_PjH z|Dvj=XrUD8WCI!k&sR*5kA}v!pSNfJ6<IEJ=yr%Ul7estl~^=#V{VN2CpSP8r8wXr z>T$a{bA%j*5fQuxo)|>jZr1{YRBA-{1CJ*HoZICJnIoNCF4LOJQi(<*B`9&BQ0dhg zYo(KD3q<dDK30Jnj^of*LV-ZR+!#3wqPz#EaOo)mPN(zS97+20!yp>N#m*4FIU=Af z#HdEyIudfZoB=prjNI`t<e#W9MZxd)7yi=N)=U1%xA~vu4`}JQAOw$Lx&QzG07*qo IM6N<$g4z^C1ONa4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_update.svg b/web/pgadmin/misc/static/explain/img/ex_update.svg new file mode 100644 index 0000000..bbea29f --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_update.svg @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +A0/ouJeMuOzfAAAAAElFTkSuQmCC +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_values_scan.png b/web/pgadmin/misc/static/explain/img/ex_values_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..15b5ab4079cb8e2c015b4f5f10a3dbf8aa6410d3 GIT binary patch literal 913 zcmV;C18)3@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-siMiW0 zh{12o?m@ljMZW2E&hL59?@+?(R>SIp)9{Ja@MXyCYRT+x%IuWb@tNB3d(Q2G(e0$& z@u=SNj@0gw*6*+3^985jNWbYDuH#$9>o~XNP`>9?z~@=P=Z4YkYscts$mx~W?|Po8 zrNQK8meIkFHu36*?c-qX<6!dYhx6)(@8e(Z<X`jahxF@*@Z?|d<X`pchw|iK_Unh? z@Av20E9lxQ=-Mjk+bZnaD(>4V@7pT#<zLt8_37Fw>)R^r+bZweD)8JY^yOdH>GbpD zU-ji*_v?rF>xbLDiPY)z_T^vG==1U1D)QVa^V}-;<zLa~^7Py)_~l>q+$#9yU-|2Y z`s|0!=JL+v^7-ap`|O6y<?;31D)-$g_}wY`=3mR?@%G&+`{rND<M8?2DahmS`Rs@M z?1snV@W$fr{N`W%?1shR@B7{<{N5@3=3n>SDf-<h{^no8;O_n2DgNw+z~An<+wA_{ zDgWkQ)amoS-tDc{=`>ap0ssI20d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_ z00FH@L_t(Y$L-b0a)Lk*24Ek?nFomRW_gGUK~X^z7hFIQqoPPyTuOQNU}g{;#Yj~u zhm?Jq%hywM|1~5M&-$-bf~P9QA@C)YD!#&4B$dhJ^6-HRlK><UDZb@$)Hi|e6h+aI z7lL#eAd=5jtC&#LT8)Xk5M;BM1g#-eV_6OzX@=ukmluLU0gw}e6wC6MaC~zhM3C?# zXpU=qVA33nA0Xiih4FYO5~N%P_eS3qM6pMZN(IEs1gO_R%)p!pq$!4J!B~W0dA{*T zU_hti6P|CPal)1$2<_;=bi0@Y8wgGI=I8hOm;|k%FdTl$=-8HJWkw8nG`bFqIFuv> z5m{ALg&>p3bzpku)=*JRlO)sW-M}cOX=((S&+i6irfAxdAd5xpz^qoW1LG6e7Dc)D zP+)8u6H)Rf`%_@fM3(#wc;Boj%jm#tw?0u-yn)kXbuBtDXA-pbh^`yxxHJr711}%G z-3~o|;r(g)dX0&(b{s2Az~Sh+#{;pMQ)_F3i9?ViuwB>2PwdUWSk8WbK|JGSEO{p| n8_Tjb@b)wQYk!?*{c(K(wSJimSdJ6(00000NkvXXu0mjfih%ky literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_values_scan.svg b/web/pgadmin/misc/static/explain/img/ex_values_scan.svg new file mode 100644 index 0000000..5328679 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_values_scan.svg @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAABHNCSVQICAgIfAhkiAAAA1tJREFU +aIHtms9r02Acxj9vOuKv48BDmAgObHCQkziHwq4iCGtzUWgv/gH+A549eN0fsIsDT9llIHgcuqnb +rTDWKRsMRw/C8OTaZW3jIWubzOTNmzXd6ugDLTR98/Z98uT7fZ68VLz9+IPLAO2iF5AVRkSGDSMi +w4YRkWHDpSEy1u8ExbElr1Zx/jluWDZLzaLod35V9E2kVnG4XyrQOqoCIIDcFZONRQfuFfudXhl9 +EwFoHVVp1TcAEMJ/RWGQ6kmJTFy95q1sHgAwOzXOfqMe+WPi5E0EP0egVnF4UCrQdqvdYznd5FsG +6kmJrGwe8PrFXQDevP/O5OT1yHHihITKJW27VZr1jUTSadVLvLUOj9uJi8vpZmhBOd0EtmLHB0nL +1Js+Ua8zRtNNvsaol0jE8zzp94Zls754+sptYVg2NKPPSSLR/W23SrujnqT2IINiX2oWReT9HUMi +p5td8xKAuJKsXrD+4pBJ11KFYdl+YYcQr16wAybVYCKR5ApRR1r1NN0ECNRInjj1+q6RQcGwbL68 +U1cvWZEEIoMyubTqZRJRpksFWoE2mZO0yUEhk2JvB9sk8ZH6wiIKQEuxRELeELOkWsXhYamAd9yL +KJpu+rUwyIgCgAKRbmtU6Pfesa9e57y46TOPKG0FJppuhlxXU4goPjxpRJkpF8DtPR4IPc9qjHoK +7Vf+vWHZfmGHIDE5fBXEyQWSKuhW8err/jqQP8727SPpTS4fqichMbke6WScq7Mbls1aCpODMIm+ +IkqWvp5WPV+tQEf8XyPKapYRJYnHpYooM+UC3qk2uZaByaWBgrMn31reqTaZixl3oRFFBaptslZx +eFSew3O3u8c0Pc/n84go7bNkLQk8d7urnhDnGFFUoOn50IJkT3IdBB9ho1CrODwuz0FAPaHn+ZQm +ogQ35o6aPUvc2Tn0Tm/UpW2TquESAHcbr7F+dmdf2TzglX2HX39cfjf81Tx/MsHNGzrzzm5oo+4s +Jhe6DRPUU+0AkURmp8aZd3YpPb3VG6gJ5p3dztap4vRhGJbtF3YIKgEzGZFE9ht1MTs17i1++MnL +Z7cBWFjek+7/qiCtegTU63xOHVE6ZBaW9wD5JvYgYFi2X9ghSNQb/fNhyDAiMmwYERk2jIgMG/4C +m6uK9JrcxxgAAAAASUVORK5CYII= +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..1f858be1cee3f5d8f2b67f55d730e6d3f43e9b42 GIT binary patch literal 2021 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_window_aggregate.svg b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.svg new file mode 100644 index 0000000..096f296 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.svg @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..b51e0b3f4c61ba166b69bd7f32cb23dc8428429e GIT binary patch literal 1965 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_worktable_scan.svg b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.svg new file mode 100644 index 0000000..38f1f9c --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.svg @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="50" + height="50" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,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 +" + x="0" + y="0" + width="50" + height="50" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/exclude.png b/web/pgadmin/misc/static/explain/img/exclude.png new file mode 100644 index 0000000000000000000000000000000000000000..bd62eef6410d9315857d2e6d246770e8b65b8f47 GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47y|-)LR^8|wi}<ymTvVw_QrY1 zLC3?d^*UDhFWLA1|9`)wM`KREbvXQ5A-=(6%9fR9ZhU_6^4^pwS28lLWMw^=HS5>= z_isLZP1<@%wQ`Qjk=K%*nNgG09JqAnY+~Zm($d$dsZT2^E~KQ~e)?Lsd6{J1L`ko# z8QYH^XzhAZSorVPuP+-md|tBT-`~HFYif>6nkJPuNuqp?YIOD56Ib^8`rV6+d^K<0 zzkmPUtXQ!pGFqZ!hGg3swe*g4XK!wIaz5qe_HfFSrwbQu^AC`0S|K@Qk7Uk-*~hPM zEhsq<82I=1?;BI6UhV1m_vg>S@bIm*jgk|0NG?2Of9R!T^@7Cpr%znEwc5~Vm%sly zUEQ5NKC5l*c3rqFx8Q{2nrn7@9?A4<w%>5&&c`3`Z{FOOoV;9Hdxfs<!JM4Ox9?6m zenWfBW$A4XY?hzYUUH^<`Bv54PXhWDq@H_cwegx-ao6F7A05CjWh@Eu3ubV5b|VeM zN%D4g;b^-zwF=1LEbxdd2GSm2>~=ES4#-&V>Eak7aXC5R07H*Y2Gbdx45l?XZ+LiQ zWMmY~)Ws(}c=qt=V{riyAu&Nw;pq&V9$ucOPn<e=Qd>hyv$&ZhB;@K9Q<JS*N=v?e zImpD;=5|bN*|M}_&%~xBFluK@M_UI6S4XqEt8Zx7+`W4C?)K%=xA(7?_c&m$V4z{4 zVq&6Wqh!RTA|NX)Ek1w3j45*_&6>t1bmBw`i*--4qPDWM%7n?><t2V{=CjN{U1V)w zV3-jtUHUai{xs0(swJ)wB`Jv|saDBFsX&Us$iUE0*8qr2Lkumf3@ojTjkFEStPBi} hcbK)IXvob^$xN%ntzp~MJ}aOG22WQ%mvv4FO#q89Jv#sZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exclude.svg b/web/pgadmin/misc/static/explain/img/exclude.svg new file mode 100644 index 0000000..7dc1378 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/exclude.svg @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAghJREFU +OI2tk89Lk3Ecx1/fbY+pe/bjwUfWUpxEDekgCB0iKDoEQUFdFBKDpEP+AaFlFy8Z1MGbCB7qolhG +XUJvhTCLyogOw4mw2cgwmzN63B73PHPPt1Nzy9vqdf6+P98Xbz4f+B/cXzHk0PScrCXrAXi/bZOT +ak2fuwCMkiSzvsmVqddlC1nB36HL02/ktaWsLBtIwEgs8009ydOPK/Jiq8ba+DhmPA4uF18mJ+WR +nh4Mdx1DsSSxxQ9EItF9AwDrxyZRp0CozsPq8B0OpdOESiVCxSJKKsXy4CA/d0yWPsXJ5fPsyYoO +ABCCs8db4OULQsEg4dFRzPl5ZC5HU28vzsgI6efPyGb2kA3e6hIBVE2jWfMh3y1iq162pqbQ+/sB +2J6dpZhMUkiu4bScQQSCBwcI1YdQFAr5PFtWAbdplh9ZlsVWNovd0IjwB8G/P6DcwY5ST9Z2cDq7 +ML1eWgcGWJ2YIDE2Rrivj11NQ3Z2QSAIPn+1gZQOBIK8/Z5j4MZNvl6/yqvubnKpFADrCwsYvwwC +w/dQPmcpetVqA2lbuLUmUqIBPdLG+SczeHQdy3Gwgfr2dk49eszKbgmf6sXV2Fht4GQ2CBwOc6Gj +jWOBevFnkSqXRwghbs/MSQ0dW9GqDfSNBKdPHOVuh19UBioBeNB7SegbCZpNg38ieuuhPBfL1HR8 +B/gNAqjSuTgH4AQAAAAASUVORK5CYII= +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/extension-sm.png b/web/pgadmin/misc/static/explain/img/extension-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..432d2f44231c1f88e787091060efc5125d80ef64 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E0BJDv+cp5$Qv6qzrVk7 zW3&9@vzBik`G5Ho|K-)uTicc2-1GkNGyU0x%oo?3fBedPak1gnHlr`^;(z|izO~Kb z%lm|1zjI$+bN~H2|Mm{mcMpR9{3*J*S>f3^`;Si}e|^pQ`={jETDdE$#Qyy)dv><$ z|KAGswyocQwlbCk`2{mLJiCzw<Zu>vL>2>S4={E+nQaGT<aoL`hDcoQ?f2wsP!M2o z7l{eDQ+~(c|9@BE84^1Kx361bY|Bu`qQb-J62DBxZ_<p5BE`pwna}6wxpa1%>e!Vz zahdU=*X&ESFOpJE*&;e)`qd3*DpaT5u9JDLS%3P((k)@<ZbaLzV+h!Of4=?`KK92q z=3fE@l4^--L`h0wNvc(HQ7VvPFfuSS&^0vDH82b@GO#i+wlXo*HZZj^FqrpFZxxD$ o-29Zxv`UBu152<5plTB<12c$*Q`1A&05vdpy85}Sb4q9e01}k2!2kdN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension-sm.svg b/web/pgadmin/misc/static/explain/img/extension-sm.svg new file mode 100644 index 0000000..3871e60 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/extension-sm.svg @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAU5JREFU +OI3FkU1LAlEUhp8r0aeIFg2WAwalRURFmxZRa1u3ate2PxAtW/U7WhW4rEWu27UYkHRhWmCgM+hQ +SjR+ordNjFrDREH0wtkc7nnOe94L/y3h1DTvT6VVStGoJAEYDawzt3Mh6pW0HAusCFdA5iosJ2Zn +GZ9WGPH7AWhWq9TMMpauo26e41W2hCMgez0vJxeX8IZUR7tvxQIv9xmiu49fAXryUHqGs/gXoq43 +Vx+y0N4muHYiADw2Xb/FG1QReFzLG1R5LSZs4FCPPQxCIIQHV4nB2OzXvlAMyzC+dWAZBr5QrMfr +p+USETm1tIpPDTsufy088Zy5IxLL2XMDfmc2zjBTGuU7Datk0G226DZb9nYzpQ0Mf8qAvv/Nk7/Z +l0Xzkm6nwfLeAQDtes09Hyfp2pFMxxUpO8cyHVfkzwkfSscVqWtHvwf8md4BuVJ12ly1hjUAAAAA +SUVORK5CYII= +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/extension.png b/web/pgadmin/misc/static/explain/img/extension.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732 GIT binary patch literal 996 zcmV<A0~`E_P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%`cO<%MQ2zLf_6I6&9|zdd99>-@a*2m!Junh7N)|bRf|-bx|zVboSKha_w(lG z;mc-L4XVVcQjb)R!IoN>UTm6cdTlP+)48aeY_F(+!qvh)fIq$I$ak@QM1Demb2p-y zZNIpg%*U?Z+|0eUmR?Q)@#@yLtA3u9XFhv8mdv0tb~C!Ok)4xckc3Wsa4?*aUD?pH z@afX-<;s|gP-<HecxWLITMn+{ye)Dq{QLL&`11Mo?Dg>A^X%E{;lk+My5`xk<JGC) z(V?J^Pa0qr9%URUZYXJ}aH`|EXsd7=V;MkvKHbcisFznYY9*e@qsi^kq0p+c;k~!# z!?5MPqv5li->#6?p?1NAale3n)0NuDkgb|nMQ$vEwur;)&X(P%klLe(*qwsbn0(Ze z&%lqBg+*3S1ZY?dnutTImr{GNfpyZ2etkM9XCNqTCtr9wihVOAV;iN_u6D(TK#xcf zTn`v!7(bOtw4`b=XCQ>Lht=`it<|(#mtSF?W<QQcm$;T>m1BZ;G0*SUx8%WGt7&4B zV3D+tb8RIwgF3Luu#bN^7G4v==*yVRp-_@kjmeoSdoaG!zSzWv!K`UHUKC!MVuZSj zaIAJVdpAyF9vxyClh&g+jY8GGe$u;klYuouT@*iVD?w)>Y;7EsekVC?DRR1gZ_tQZ zyKv99ZOyY~z@}84hBK{_JHn(!l6fLVbTnhFZfMSfV$6Lul0qhGC2*Z?NP<TvhBL~q zUB|0c#ivccpg)Ro98G#WT*`P>$a6}(W;2>aI;l}Wz+t|fIeljlScFSfreaXWZ%f2# zMZ#t~zg?k^OOAUphI1*4cr3V}Qns8&igY1@Y#D@Y7H?b$T8UCtsbn_2S%i2!rk!)h z!>EaMCcvamyR?(W!KK8$qF<3+9BCaAUJ)8<9X6LmEss1DV->ZTL3e2=8EP9)hfaum zLy>wXERsEdsDEo(3zmE$ex`jsyImG&7=LOOfol~TcO*%INEmJ%7i}B|YRn1%0004W zQchC<K<3zH00001VoOIv0Eh)0NB{r;32;bRa{vGf6951U69E94oEQKA00(qQO+^RW z0~-xG4!&HBF8}}lR!KxbR2b7^U?3j2xS;VvLXbtwTz~>0W=QhVA)yH_FkL{}1;huk zpaKCQKz@=7s`{i97i0@vl2TS8w1C7?R&G7y;)1Nm<<OZkC{A-h<6}A<CjbDaP8qDe SR_4e60000<MNUMnLSTaX-^L37 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension.svg b/web/pgadmin/misc/static/explain/img/extension.svg new file mode 100644 index 0000000..6ab57bf --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/extension.svg @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAPJJREFU +OI2lU6EOwjAUvDK2NCg+iB9ADI2ZBgUSPCwEgV0QOMxISEio5R/4DAyubCyjoRgGW7suhD35+u7e +3bUlg34bdapRC/0rAaOOZNSRfxEw6sjADxH4IcpIjAQ766ltDfwQO+tZ6DVNBC2bYrs8gosYXETg +IsJ8NkLLpmA2pJukRFOgelXBbpKSDGhUcFidcEmusgt8wPwRFWbyJFoGNxG/t3/B/N0rK02BN+nB +TVLCqCPH08XHhmo1U1EgUP3lM+gMPbD1VrtGYnrK+TA7Qw+RuAMAzpt9dQZ5NdmgCVypoEyNCgYq +HpKqxnRW+ze+AO9gktborNU6AAAAAElFTkSuQmCC +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/extensions.png b/web/pgadmin/misc/static/explain/img/extensions.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5 GIT binary patch literal 1017 zcmV<V0|xwwP)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%_fSk!MS^xZ(#^N3p?R&Od+_Yu$ibj%T^6RorB#bmn!1_5x}2JiUH9|m=i$p{ zRt>7esZx(rkHMB&m|kp}YkF-i+S9qHoNTYCfx^|oK7c>H>Bx7neMEjjfO9vZnQgzg znaszo-`vc-ww7K_0rBeAwyS=gm1jPCJeJI$Gj=n&vyq*XV~~VSeQ+?GkzLu)v+(KC z?&Zpui%@D?5_o7K5L*te<Gd|$E&TiU`}p$t_U!fW;PdR+>*2!a-MZ%4vg6gM;L)L= zk53w479M3BDQ+lfsBo&|xoE3!8)F$jd_LXGn5dUmHEJcE$)m~b(xK3*v*EqB=fkk& zzN6u@o!_pI*P(X7g>k=tf76xP$dIj?SVe9ugSLpn>&}+lsF2#DiP)Wj)|h<Mlh449 zm4!uCPy}dL4Vs8UtCv!Hv4M5cjedPPC}$ujZ6{xNJBocXBx4(;)vk8Mhd_@=5nK-# zWf(t|O0=YEF=rrzvxn93+^yBLT$f*Ao@PIeN0+#kWR+urcQMcJ*SF-sT&rnflVFjw zkaKM%G=n;@$*_-qITl_M!syGG&7n||RE^1*D|;}$)4tfmhrz6AIbIZAnqq{yi*T%V zHhVWtV;&u18I#tdIE_NpzkbrYc9VfMLtPX<ZYx1&B5Z9Om3}8VZ7FiPes9o-TDx%1 zw{6X{Wx%FXorW{5k~_krMv{3VMsze|t!`+}gJR5mHj+XnY9(-;Zb*VhCx$c1uU*Hh zRmG=Gz@R^havV*1JY33nR>*Toyk;|+MLMZbK)_+XojHAH5m<yvR;FT5#&1i+YDL0k zJHK6_k4uhwGlp|1i+C)!pi;J+M~ZYIf@~RtZ5D4_30jF#R;gq*y;+2KJ*J&=$it|K zbtb^1PrI~}#=)h;zM@}|T^wm05?&D+Y8^J0MJ<m!6k`>&nL&4HC>d%SP=`*4d_$3X zCoGaZfT(|KS__tZB7UZQKD%8OXc&KL7J+LO8+Rm0f=C!{9T#mJ7UDFE00001bW%=J z06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru+XEXB z6Cp(Rbcp}}0B%V{K~xyiU68R2z#t3+nS(tt!3~hY^vGg42FL=`EENNm0{M!6-y1;) zQxFazvL_cK*b<_okFg0d8Hc#V=Eh`)h+yZmplehnlNZEdtgQ@hX0CNeIWEpxw!oyN ndc~tsp9TlidOzOC&-)*|KH)3pD2ngr00000NkvXXu0mjf<KNUz literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extensions.svg b/web/pgadmin/misc/static/explain/img/extensions.svg new file mode 100644 index 0000000..22a8206 --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/extensions.svg @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAVFJREFU +OI2NkzFLw0AUx3+RFEo/QAZdO/oJpJ9BOhakUHAJBS04tMUqghqKgw4OIUO3LhkKgrPfwcWxqwjF +7ZooeBCX3HlJrsU3vTvu/97v/+7OuR4eYItotcwAfK/pWA/ksbNJHAYxYRDrQv8q8PD+ltkE24q4 +5qJRqzO/e0bIFCETRlfHhEEMQH/SyWx23LJXIVN6wzaNWr1wMAxi+pNOZS4uwNP9Cx/fn1kICJlU +SIRMuL05tdK4AGuZ0p90ALi4fESRCJlwcn5kpekN29nZ3r7j7PY8PaCcJC/w19lGoy0olGi1zNYy +VYgADMbTAo0Sm5rCLXRHhzpXNGEQa7H4SQpWfK/puOZC5SaNKRb5nhluZcdCMxhPtQ0zKhbKNOqN +mDNo+V2iaK4H72z6TGYXlbf8Lon8AuB1tsD3mo71M5VpFFFZDFtmYCsUzRaVp/wLVVvmqzUDDg4A +AAAASUVORK5CYII= +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/exttable-sm.png b/web/pgadmin/misc/static/explain/img/exttable-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..acd43cb8abab6ef38daf34ff6d7544153a11dacf GIT binary patch literal 612 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47`X#{LR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)^XY$8$A0G@_?f)(TiB-0o~u9DE`4h_ z@3s2Om(8dDdI7mh-fGNz8JxJ$(RuCl>$mUSyLbQo{YQ@;J%0Rn>9T9)mKA9e*Bv-; z!q9k*y7s}c^63vAJOIkOd8|>@*q@f(clYkyWy_XDM0Trbo^<nAscUdhS#3sp`^5F@ z*S~u8DlvJNy7pxi^{qR09)J1r<?Gk4&!4|-WV%sNW#!y?Ya^o8sA?W7EL!yO<Hxse z-}X<~s-}6=(71d4{Dn`SK5cATs;+%VU9<bdiL;%Z6I)tVJ$drv&6_t59=vw<+ErTC zQw{Rh4~>~Gc%JJ_00swRNswPKgTu2MX+REVfk$L9koEv$x0Bg+K*j`57sn8Z%gG4} zOa@Af9Sp+8+}hIC?Ck2|<}MBG)BEEc0z4vIL{>Gq^Qb83DJpS_PM9=p;?&9E0U<$c zTq{<rTA7`ZmHE2Bfwko87hay;9$%lc3z#+)6+IK17IrPoEP&B6+Pa$ET|Heqd_}|T z-R;Y#Z{6O%UOwc2y~2g=!)h89Dk9JL?rkX8V67z4`B96(W2)e}i60vRfNoPQag8WR zNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTd cHGouG8JIydoSGiG2B?9-)78&qol`;+0LVQH?EnA( literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable-sm.svg b/web/pgadmin/misc/static/explain/img/exttable-sm.svg new file mode 100644 index 0000000..e1763ad --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/exttable-sm.svg @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAbpJREFU +OI3Fkk1IFGEYx3/P7GwTnqttD0vZSSJWw5SdoK51DLRPg4wMsxACsUsQIh3qFJVG5c1jdPADgq1L +KUTWQfPQwT1sGfkR0S7tsLuzM+9MB3V0/Dh48oGH9+V5+f/4vw9/2OmSlUt1/7y/HWH2VlwA9LXD +DjNGlTjEd9kkjDJ7DMVuHfCX2Nl/MPxD4+3PVU0I4PmQU1HmShpjFQPLVhSW26ooLNuj6HhUXC/Q +aBvNbfyJrBnLureQgy99o/yddXnWl8QwIogIkcjSOTZe4MnAIA0XGnmnm5s76LwSI5/PcaZ5jucv +0ogISsG16xP09C5Sm9xHz9nU1g4Sib10d1UxMvqZoZGTTH2dYH5hP8XiH9qu/qKmphpd1wG1OUBE +ME0T04Te+xk+fjqMcmfpf1rL0bpDiAgi4S1o6wH5vEvTuWnef8hxp2uGY/UlOm/7PHiYxjAMNE3b +GjA0/I3zl37jezPcu1vm9KkUjx+d4PLFLG/SB2lMvSST+R4ChJJ4w3qF48RpbT0e2I1Go4gIluXT +fnOS5JFpXh9oCZIYArSnYjgelJ3V4BRsFQTKqniUHIXt+gFg5+s/qYOxr5VB8/gAAAAASUVORK5C +YII= +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/exttable.png b/web/pgadmin/misc/static/explain/img/exttable.png new file mode 100644 index 0000000000000000000000000000000000000000..5d84035feea62d53d457481178b1bcbe9622f856 GIT binary patch literal 793 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47;6K3LR^7d#i`GGFZ`c${`aEG zUw7Sjd-49u`;VVLefIp>vuC#+K3#L}dGf{=db3}2pa0)_=3m{3Kc$C%<?Q>BxZ_*c zrqAAMJ~%9YXTIQ#?wnU@GhViy`J27(hvTw$W((iw&U_Y~)1HyF{qEhn_wL=hfB*i2 z2M-=TeE8_mqsNaQ8yXiV>iW%}zd>1TV^GL$BjYL^{S(WU9oVt+prXnmSNFZkm#=*C z<jL~o%k>TF^o@>PyZ-vst5*{zPLflcU|_QU>a|B#uU=JF?bJ2cziipY_3PKae*OB& zm8%-sEqaEB)ikG?m>;=w=lPpAZ{EIr`|{<>zP<^HDjPJkuS}Y>_5J(zA3l8e^y$;P zckfoNT)BGn>N#`fDXPqIbUAEeo3EjBs<&_JrcIlkKYzY=?-6CSwcft_U%!6i?2@ga zbAH+K$Dcoc{`&RnzI`WD)Hj5LAKkcd)7Gt9lT#YiwN7;R-um|K+wv9LmDM(Tcy0Rl z@#D5_+u{=nRW-JDc3)AL{8UY|HzVudq)BroPg$ri@$mwIO;dmoz*rLG7tG-B>_!@p z!&%@FSq!8-z}W3%wjGdh+0(@_MB;LCLV^n;4-Zd|&l#OHId5d<%!#>Uvqyo^u8z@B zF;Otku#nSp1DBm9qhscRhMqMtE)H>yfu51Bp}w)6&cZqimabjQ@@VyoS1+4cMR<97 zd#?KUoIRtfbCAhvS=cqRZDrs1`uxr%FfOPQ4>vF8_xIM%-_X$2-@kPI{CbCkfC7#P z2U8Or8zmzxD>XAS4xIy%;`1lWcrs_sq*>GW#5zu&ICF}R^VG?+r}Y`QMZ`qYkF!mE zGG*G-@CFvG)vNY8H+eN(zQmoCbx`Y7z#e{vFBY0Te&TE7f!<Rsag8WRNi0dVN-jzT zQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTdHGouG8JIyd UoSGiG2B?9-)78&qol`;+0Q{<O$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable.svg b/web/pgadmin/misc/static/explain/img/exttable.svg new file mode 100644 index 0000000..d2efe1d --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/exttable.svg @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAk9JREFU +OI2dkl1Ik2EUx3/n3d7XGWbmyLa6UbRAKUgqSITFcnQRQZFKH1I3hVYWlCUSiBAifUBdJEqpCV1U +5kVCN13UxYKRRBeJXphdOCpsUFqNzXR7v7pYjpYLoj8ceM4D539+5zyPAJT0RGz+Q+FmrziXkjPV +HlTboMCZxKMusjbHIN9poTlASPnHdZvxOYWnH4XXn1N1aQPLhpjpYDaRw4SusqBbzCct5pNmKnSL +hYTFD8MiYdjopgWAkgllZzmlJDbYAphGxn2aYOzuVVZaW2i9sBERyRq6rlNbf4t4chpO3skkCGwt +59nzJK1t06mOfxSbpkld/QC6cYiuSy1pgrSBz7eZnu4C3oxFaDoVZnT0FSKCoiiEQiH27R/EtPcy +PFRKIFCx3EBE+Pb1E+fOfmfq3QTXbhQRi0M0GqW94wMWftoufmHqbQgRWb4DEaGqqgoRoaYmTt3B +EQ43OFlcHGd1YTVD90vJz3egKEqGQQZBbm4uLpeLoqI1NB7PIxabQ1F2cqwhitvtQtM0NE37O0Ew +GERRFKLRGN29eRQXu9ET/fT2NaAbL9lQZv7al285gaqq+Hw+Cgu9XLm+ioryUoYfljPyuJ31nnv0 +D64jPl+J3+9HVdXsI0xOvqfp9CyVlR4aT8RwOBRUVaXl/B6qdzzhcucMt/si2UcIvhijvcNgQ5nC +0SNziJCxsNoD2zGMR/T1B7CsJKxwpxoDFHfP2FrvELv82+jq3JR+/98/0lI+MPAAUVRuym7Czd6U +fUlPxLYNA3Gmgf5J4Wav/ASfptBgzLJqagAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/img/exttables.png b/web/pgadmin/misc/static/explain/img/exttables.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dfbd454ed33727bd1deeb87c62f8671f6a5a03 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47^MPyLR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)(1uT&ufDx|_ipp)e^tkR=O6f)yz^Vw zrq7<MKiDpPYdG(<`plR2?%iuX{nra9vgEDdjF%cSU*5le-z{*Hjoqv(SFS&L^yu;9 z$BCh54YV)SY`ps5!GohmFPT|vP}AIAUOws6@q1>vXAHE?^>wU&`SRt%hYy!6TNV*D zT}|t>v;9UL?W?Amt7goYwSN8jSFc`8IQ7}h=Aef5HBHT(=Pz7){rdI(-PetE&Kqf+ zTC?J?x9>_dt@Dk|J3fB=`1bAF+~nQb+SeRSH>_B(;_1_;Rn;?8HFg`BEWUQ_zJ=bg zri$H9o;-Q;=FOu=PwX9+YwPW<2KnxXa>IqjgMEvDp~F}b<QL4~@a#q!ki%Kv5m^kR zJ;2!QWVRiUvDwqbF+}2W?0HwQLk<G27xhdW8XmB4zY~jTVks}b`QPk?8Z+O@ht}mE zxDUR+@ZDiy$V$_wu1ha@gBJAuXUmw$IQdLNWLm+2wv7?FW$l-rva#qG$_eeUt7l;6 zYfsQPQ#3I{XWjwDPG7CLC)J97I!!#j(8XtG(AulgXTzi?C<q+hI5%(o`R%TodS@Ig zFq!9*{+X5YhEDkFv(xUs<#&JSY%y0q+H23fcl??hCZB62%C0l7Vc_x-dugW}eiG<> z)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!XjU}|MxU@=ow4n;$5eoAIq iB}9XPC0GMUwUvPxM8m1+p=*E|7(8A5T-G@yGywoZHZsuw literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttables.svg b/web/pgadmin/misc/static/explain/img/exttables.svg new file mode 100644 index 0000000..4bdfaed --- /dev/null +++ b/web/pgadmin/misc/static/explain/img/exttables.svg @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + version="1.1" + width="16" + height="16" + id="svg2"> + <metadata + id="metadata8"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs6" /> + <image + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAgdJREFU +OI2dk0trE1EUgL8zmThp2mw0bVpFMFoXareWBMwfqOJCLYLQCiK04qNF3aqb4roVIm1xJYoLkaJ2 +5SKCbkoVo6AuRE1NjUkkfdg8nJk0My5iYh4byYHLuVwO3/kOnCv+cNLmPyN2vkca31SAc0EfbinS +s8Vgp6bj1Uq4VMAus2Mb8PibwrM7Kfvt2W5pAlg2ROIG0US+gV9bW4b5w0m71kStXKKJfEsmKsAB +1xqtmqgA+13rgLslE7W2T63JWsnJj98KL0yNnFEi+/fkzBI5w6JQtDA3LRQAkbJi2aRetWkQGzCt +6lBqLaASkYl5Cisppm+HcLs1RASHw4GIcP3yT6IfnZy46eD+9631BpV84+ouTLOLY4NLzMzMIyKk +EpscH0gT/SAMD33hYsDbbFDJ3d3tjF8q8GQ+ydzTIK8X3pHO9NJmfWV0bB2fr7Naq44d7GAuDZCr +AwWDQQIBm9HhZeKZvYi1zOyDPrb3bENEqrXKeL9Hxvs90miy9Fln8OgvMqttTFxbYXfvOidPGUzP +RtE0DUVR6jdkcjFrA0y9ynHkzXsiCzvocn9i5IpOKBRCVVWmbs3x8NEePB0p7t09xOHnLpp+lz+c +tH0zMQYG8py5sK+q63Q6EREKBZ2h0y/JrHgpjPQ1AyYXs7buaKdogV78tzhZo1RdqJxpsRFPYHX6 ++AMN5/e0m/GsSQAAAABJRU5ErkJggg== +" + x="0" + y="0" + width="16" + height="16" + id="image10" /> +</svg> diff --git a/web/pgadmin/misc/static/explain/js/snap.svg-min.js b/web/pgadmin/misc/static/explain/js/snap.svg-min.js new file mode 100644 index 0000000..6567d19 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg-min.js @@ -0,0 +1,21 @@ +// Snap.svg 0.4.1 +// +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// build: 2015-04-13 + +!function(a){var b,c,d="0.4.2",e="hasOwnProperty",f=/[\.\/]/,g=/\s*,\s*/,h="*",i=function(a,b){return a-b},j={n:{}},k=function(){for(var a=0,b=this.length;b>a;a++)if("undefined"!=typeof this[a])return this[a]},l=function(){for(var a=this.length;--a;)if("undefined"!=typeof this[a])return this[a]},m=function(a,d){a=String(a);var e,f=c,g=Array.prototype.slice.call(arguments,2),h=m.listeners(a),j=0,n=[],o={},p=[],q=b;p.firstDefined=k,p.lastDefined=l,b=a,c=0;for(var r=0,s=h.length;s>r;r++)"zIndex"in h[r]&&(n.push(h[r].zIndex),h[r].zIndex<0&&(o[h[r].zIndex]=h[r]));for(n.sort(i);n[j]<0;)if(e=o[n[j++]],p.push(e.apply(d,g)),c)return c=f,p;for(r=0;s>r;r++)if(e=h[r],"zIndex"in e)if(e.zIndex==n[j]){if(p.push(e.apply(d,g)),c)break;do if(j++,e=o[n[j]],e&&p.push(e.apply(d,g)),c)break;while(e)}else o[e.zIndex]=e;else if(p.push(e.apply(d,g)),c)break;return c=f,b=q,p};m._events=j,m.listeners=function(a){var b,c,d,e,g,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,g=m.length;g>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[h]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},m.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(g),d=0,e=c.length;e>d;d++)!function(a){for(var c,d=a.split(f),e=j,g=0,h=d.length;h>g;g++)e=e.n,e=e.hasOwnProperty(d[g])&&e[d[g]]||(e[d[g]]={n:{}});for(e.f=e.f||[],g=0,h=e.f.length;h>g;g++)if(e.f[g]==b){c=!0;break}!c&&e.f.push(b)}(c[d]);return function(a){+a==+a&&(b.zIndex=+a)}},m.f=function(a){var b=[].slice.call(arguments,1);return function(){m.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},m.stop=function(){c=1},m.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},m.nts=function(){return b.split(f)},m.off=m.unbind=function(a,b){if(!a)return void(m._events=j={n:{}});var c=a.split(g);if(c.length>1)for(var d=0,i=c.length;i>d;d++)m.off(c[d],b);else{c=a.split(f);var k,l,n,d,i,o,p,q=[j];for(d=0,i=c.length;i>d;d++)for(o=0;o<q.length;o+=n.length-2){if(n=[o,1],k=q[o].n,c[d]!=h)k[c[d]]&&n.push(k[c[d]]);else for(l in k)k[e](l)&&n.push(k[l]);q.splice.apply(q,n)}for(d=0,i=q.length;i>d;d++)for(k=q[d];k.n;){if(b){if(k.f){for(o=0,p=k.f.length;p>o;o++)if(k.f[o]==b){k.f.splice(o,1);break}!k.f.length&&delete k.f}for(l in k.n)if(k.n[e](l)&&k.n[l].f){var r=k.n[l].f;for(o=0,p=r.length;p>o;o++)if(r[o]==b){r.splice(o,1);break}!r.length&&delete k.n[l].f}}else{delete k.f;for(l in k.n)k.n[e](l)&&k.n[l].f&&delete k.n[l].f}k=k.n}}},m.once=function(a,b){var c=function(){return m.unbind(a,c),b.apply(this,arguments)};return m.on(a,c)},m.version=d,m.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=m:"function"==typeof define&&define.amd?define("eve",[],function(){return m}):a.eve=m}(this),function(a,b){if("function"==typeof define&&define.amd)define(["eve"],function(c){return b(a,c)});else if("undefined"!=typeof exports){var c=require("eve");module.exports=b(a,c)}else b(a,a.eve)}(window||this,function(a,b){var c=function(b){var c={},d=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},e=Array.isArray||function(a){return a instanceof Array||"[object Array]"==Object.prototype.toString.call(a)},f=0,g="M"+(+new Date).toString(36),h=function(){return g+(f++).toString(36)},i=Date.now||function(){return+new Date},j=function(a){var b=this;if(null==a)return b.s;var c=b.s-a;b.b+=b.dur*c,b.B+=b.dur*c,b.s=a},k=function(a){var b=this;return null==a?b.spd:void(b.spd=a)},l=function(a){var b=this;return null==a?b.dur:(b.s=b.s*a/b.dur,void(b.dur=a))},m=function(){var a=this;delete c[a.id],a.update(),b("mina.stop."+a.id,a)},n=function(){var a=this;a.pdif||(delete c[a.id],a.update(),a.pdif=a.get()-a.b)},o=function(){var a=this;a.pdif&&(a.b=a.get()-a.pdif,delete a.pdif,c[a.id]=a)},p=function(){var a,b=this;if(e(b.start)){a=[];for(var c=0,d=b.start.length;d>c;c++)a[c]=+b.start[c]+(b.end[c]-b.start[c])*b.easing(b.s)}else a=+b.start+(b.end-b.start)*b.easing(b.s);b.set(a)},q=function(){var a=0;for(var e in c)if(c.hasOwnProperty(e)){var f=c[e],g=f.get();a++,f.s=(g-f.b)/(f.dur/f.spd),f.s>=1&&(delete c[e],f.s=1,a--,function(a){setTimeout(function(){b("mina.finish."+a.id,a)})}(f)),f.update()}a&&d(q)},r=function(a,b,e,f,g,i,s){var t={id:h(),start:a,end:b,b:e,s:0,dur:f-e,spd:1,get:g,set:i,easing:s||r.linear,status:j,speed:k,duration:l,stop:m,pause:n,resume:o,update:p};c[t.id]=t;var u,v=0;for(u in c)if(c.hasOwnProperty(u)&&(v++,2==v))break;return 1==v&&d(q),t};return r.time=i,r.getById=function(a){return c[a]||null},r.linear=function(a){return a},r.easeout=function(a){return Math.pow(a,1.7)},r.easein=function(a){return Math.pow(a,.48)},r.easeinout=function(a){if(1==a)return 1;if(0==a)return 0;var b=.48-a/1.04,c=Math.sqrt(.1734+b*b),d=c-b,e=Math.pow(Math.abs(d),1/3)*(0>d?-1:1),f=-c-b,g=Math.pow(Math.abs(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},r.backin=function(a){if(1==a)return 1;var b=1.70158;return a*a*((b+1)*a-b)},r.backout=function(a){if(0==a)return 0;a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},r.elastic=function(a){return a==!!a?a:Math.pow(2,-10*a)*Math.sin(2*(a-.075)*Math.PI/.3)+1},r.bounce=function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b},a.mina=r,r}("undefined"==typeof b?function(){}:b),d=function(a){function c(a,b){if(a){if(a.nodeType)return w(a);if(e(a,"array")&&c.set)return c.set.apply(c,a);if(a instanceof s)return a;if(null==b)return a=y.doc.querySelector(String(a)),w(a)}return a=null==a?"100%":a,b=null==b?"100%":b,new v(a,b)}function d(a,b){if(b){if("#text"==a&&(a=y.doc.createTextNode(b.text||b["#text"]||"")),"#comment"==a&&(a=y.doc.createComment(b.text||b["#text"]||"")),"string"==typeof a&&(a=d(a)),"string"==typeof b)return 1==a.nodeType?"xlink:"==b.substring(0,6)?a.getAttributeNS(T,b.substring(6)):"xml:"==b.substring(0,4)?a.getAttributeNS(U,b.substring(4)):a.getAttribute(b):"text"==b?a.nodeValue:null;if(1==a.nodeType){for(var c in b)if(b[z](c)){var e=A(b[c]);e?"xlink:"==c.substring(0,6)?a.setAttributeNS(T,c.substring(6),e):"xml:"==c.substring(0,4)?a.setAttributeNS(U,c.substring(4),e):a.setAttribute(c,e):a.removeAttribute(c)}}else"text"in b&&(a.nodeValue=b.text)}else a=y.doc.createElementNS(U,a);return a}function e(a,b){return b=A.prototype.toLowerCase.call(b),"finite"==b?isFinite(a):"array"==b&&(a instanceof Array||Array.isArray&&Array.isArray(a))?!0:"null"==b&&null===a||b==typeof a&&null!==a||"object"==b&&a===Object(a)||J.call(a).slice(8,-1).toLowerCase()==b}function f(a){if("function"==typeof a||Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[z](c)&&(b[c]=f(a[c]));return b}function h(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function i(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),g=d.cache=d.cache||{},i=d.count=d.count||[];return g[z](f)?(h(i,f),c?c(g[f]):g[f]):(i.length>=1e3&&delete g[i.shift()],i.push(f),g[f]=a.apply(b,e),c?c(g[f]):g[f])}return d}function j(a,b,c,d,e,f){if(null==e){var g=a-c,h=b-d;return g||h?(180+180*D.atan2(-h,-g)/H+360)%360:0}return j(a,b,e,f)-j(c,d,e,f)}function k(a){return a%360*H/180}function l(a){return 180*a/H%360}function m(a){var b=[];return a=a.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g,function(a,c,d){return d=d.split(/\s*,\s*|\s+/),"rotate"==c&&1==d.length&&d.push(0,0),"scale"==c&&(d.length>2?d=d.slice(0,2):2==d.length&&d.push(0,0),1==d.length&&d.push(d[0],0,0)),b.push("skewX"==c?["m",1,0,D.tan(k(d[0])),1,0,0]:"skewY"==c?["m",1,D.tan(k(d[0])),0,1,0,0]:[c.charAt(0)].concat(d)),a}),b}function n(a,b){var d=ab(a),e=new c.Matrix;if(d)for(var f=0,g=d.length;g>f;f++){var h,i,j,k,l,m=d[f],n=m.length,o=A(m[0]).toLowerCase(),p=m[0]!=o,q=p?e.invert():0;"t"==o&&2==n?e.translate(m[1],0):"t"==o&&3==n?p?(h=q.x(0,0),i=q.y(0,0),j=q.x(m[1],m[2]),k=q.y(m[1],m[2]),e.translate(j-h,k-i)):e.translate(m[1],m[2]):"r"==o?2==n?(l=l||b,e.rotate(m[1],l.x+l.width/2,l.y+l.height/2)):4==n&&(p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.rotate(m[1],j,k)):e.rotate(m[1],m[2],m[3])):"s"==o?2==n||3==n?(l=l||b,e.scale(m[1],m[n-1],l.x+l.width/2,l.y+l.height/2)):4==n?p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.scale(m[1],m[1],j,k)):e.scale(m[1],m[1],m[2],m[3]):5==n&&(p?(j=q.x(m[3],m[4]),k=q.y(m[3],m[4]),e.scale(m[1],m[2],j,k)):e.scale(m[1],m[2],m[3],m[4])):"m"==o&&7==n&&e.add(m[1],m[2],m[3],m[4],m[5],m[6])}return e}function o(a){var b=a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||a.node.parentNode&&w(a.node.parentNode)||c.select("svg")||c(0,0),d=b.select("defs"),e=null==d?!1:d.node;return e||(e=u("defs",b.node).node),e}function p(a){return a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||c.select("svg")}function q(a,b,c){function e(a){if(null==a)return I;if(a==+a)return a;d(j,{width:a});try{return j.getBBox().width}catch(b){return 0}}function f(a){if(null==a)return I;if(a==+a)return a;d(j,{height:a});try{return j.getBBox().height}catch(b){return 0}}function g(d,e){null==b?i[d]=e(a.attr(d)||0):d==b&&(i=e(null==c?a.attr(d)||0:c))}var h=p(a).node,i={},j=h.querySelector(".svg---mgr");switch(j||(j=d("rect"),d(j,{x:-9e9,y:-9e9,width:10,height:10,"class":"svg---mgr",fill:"none"}),h.appendChild(j)),a.type){case"rect":g("rx",e),g("ry",f);case"image":g("width",e),g("height",f);case"text":g("x",e),g("y",f);break;case"circle":g("cx",e),g("cy",f),g("r",e);break;case"ellipse":g("cx",e),g("cy",f),g("rx",e),g("ry",f);break;case"line":g("x1",e),g("x2",e),g("y1",f),g("y2",f);break;case"marker":g("refX",e),g("markerWidth",e),g("refY",f),g("markerHeight",f);break;case"radialGradient":g("fx",e),g("fy",f);break;case"tspan":g("dx",e),g("dy",f);break;default:g(b,e)}return h.removeChild(j),i}function r(a){e(a,"array")||(a=Array.prototype.slice.call(arguments,0));for(var b=0,c=0,d=this.node;this[b];)delete this[b++];for(b=0;b<a.length;b++)"set"==a[b].type?a[b].forEach(function(a){d.appendChild(a.node)}):d.appendChild(a[b].node);var f=d.childNodes;for(b=0;b<f.length;b++)this[c++]=w(f[b]);return this}function s(a){if(a.snap in V)return V[a.snap];var b;try{b=a.ownerSVGElement}catch(c){}this.node=a,b&&(this.paper=new v(b)),this.type=a.tagName||a.nodeName;var d=this.id=S(this);if(this.anims={},this._={transform:[]},a.snap=d,V[d]=this,"g"==this.type&&(this.add=r),this.type in{g:1,mask:1,pattern:1,symbol:1})for(var e in v.prototype)v.prototype[z](e)&&(this[e]=v.prototype[e])}function t(a){this.node=a}function u(a,b){var c=d(a);b.appendChild(c);var e=w(c);return e}function v(a,b){var c,e,f,g=v.prototype;if(a&&"svg"==a.tagName){if(a.snap in V)return V[a.snap];var h=a.ownerDocument;c=new s(a),e=a.getElementsByTagName("desc")[0],f=a.getElementsByTagName("defs")[0],e||(e=d("desc"),e.appendChild(h.createTextNode("Created with Snap")),c.node.appendChild(e)),f||(f=d("defs"),c.node.appendChild(f)),c.defs=f;for(var i in g)g[z](i)&&(c[i]=g[i]);c.paper=c.root=c}else c=u("svg",y.doc.body),d(c.node,{height:b,version:1.1,width:a,xmlns:U});return c}function w(a){return a?a instanceof s||a instanceof t?a:a.tagName&&"svg"==a.tagName.toLowerCase()?new v(a):a.tagName&&"object"==a.tagName.toLowerCase()&&"image/svg+xml"==a.type?new v(a.contentDocument.getElementsByTagName("svg")[0]):new s(a):a}function x(a,b){for(var c=0,d=a.length;d>c;c++){var e={type:a[c].type,attr:a[c].attr()},f=a[c].children();b.push(e),f.length&&x(f,e.childNodes=[])}}c.version="0.4.0",c.toString=function(){return"Snap v"+this.version},c._={};var y={win:a.window,doc:a.window.document};c._.glob=y;{var z="hasOwnProperty",A=String,B=parseFloat,C=parseInt,D=Math,E=D.max,F=D.min,G=D.abs,H=(D.pow,D.PI),I=(D.round,""),J=Object.prototype.toString,K=/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,L=(c._.separator=/[,\s]+/,/[\s]*,[\s]*/),M={hs:1,rg:1},N=/([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,O=/([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,P=/(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/gi,Q=0,R="S"+(+new Date).toString(36),S=function(a){return(a&&a.type?a.type:I)+R+(Q++).toString(36)},T="http://www.w3.org/1999/xlink",U="http://www.w3.org/2000/svg",V={};c.url=function(a){return"url('#"+a+"')"}}c._.$=d,c._.id=S,c.format=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return A(b).replace(a,function(a,b){return c(a,b,d)})}}(),c._.clone=f,c._.cacher=i,c.rad=k,c.deg=l,c.sin=function(a){return D.sin(c.rad(a))},c.tan=function(a){return D.tan(c.rad(a))},c.cos=function(a){return D.cos(c.rad(a))},c.asin=function(a){return c.deg(D.asin(a))},c.acos=function(a){return c.deg(D.acos(a))},c.atan=function(a){return c.deg(D.atan(a))},c.atan2=function(a){return c.deg(D.atan2(a))},c.angle=j,c.len=function(a,b,d,e){return Math.sqrt(c.len2(a,b,d,e))},c.len2=function(a,b,c,d){return(a-c)*(a-c)+(b-d)*(b-d)},c.closestPoint=function(a,b,c){function d(a){var d=a.x-b,e=a.y-c;return d*d+e*e}for(var e,f,g,h,i=a.node,j=i.getTotalLength(),k=j/i.pathSegList.numberOfItems*.125,l=1/0,m=0;j>=m;m+=k)(h=d(g=i.getPointAtLength(m)))<l&&(e=g,f=m,l=h);for(k*=.5;k>.5;){var n,o,p,q,r,s;(p=f-k)>=0&&(r=d(n=i.getPointAtLength(p)))<l?(e=n,f=p,l=r):(q=f+k)<=j&&(s=d(o=i.getPointAtLength(q)))<l?(e=o,f=q,l=s):k*=.5}return e={x:e.x,y:e.y,length:f,distance:Math.sqrt(l)}},c.is=e,c.snapTo=function(a,b,c){if(c=e(c,"finite")?c:10,e(a,"array")){for(var d=a.length;d--;)if(G(a[d]-b)<=c)return a[d]}else{a=+a;var f=b%a;if(c>f)return b-f;if(f>a-c)return b-f+a}return b},c.getRGB=i(function(a){if(!a||(a=A(a)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};if("none"==a)return{r:-1,g:-1,b:-1,hex:"none",toString:Z};if(!(M[z](a.toLowerCase().substring(0,2))||"#"==a.charAt())&&(a=W(a)),!a)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};var b,d,f,g,h,i,j=a.match(K);return j?(j[2]&&(f=C(j[2].substring(5),16),d=C(j[2].substring(3,5),16),b=C(j[2].substring(1,3),16)),j[3]&&(f=C((h=j[3].charAt(3))+h,16),d=C((h=j[3].charAt(2))+h,16),b=C((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=B(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),f=B(i[2]),"%"==i[2].slice(-1)&&(f*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100)),j[5]?(i=j[5].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsb2rgb(b,d,f,g)):j[6]?(i=j[6].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsl2rgb(b,d,f,g)):(b=F(D.round(b),255),d=F(D.round(d),255),f=F(D.round(f),255),g=F(E(g,0),1),j={r:b,g:d,b:f,toString:Z},j.hex="#"+(16777216|f|d<<8|b<<16).toString(16).slice(1),j.opacity=e(g,"finite")?g:1,j)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z}},c),c.hsb=i(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=i(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=i(function(a,b,c,d){if(e(d,"finite")){var f=D.round;return"rgba("+[f(a),f(b),f(c),+d.toFixed(2)]+")"}return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)});var W=function(a){var b=y.doc.getElementsByTagName("head")[0]||y.doc.getElementsByTagName("svg")[0],c="rgb(255, 0, 0)";return(W=i(function(a){if("red"==a.toLowerCase())return c;b.style.color=c,b.style.color=a;var d=y.doc.defaultView.getComputedStyle(b,I).getPropertyValue("color");return d==c?null:d}))(a)},X=function(){return"hsb("+[this.h,this.s,this.b]+")"},Y=function(){return"hsl("+[this.h,this.s,this.l]+")"},Z=function(){return 1==this.opacity||null==this.opacity?this.hex:"rgba("+[this.r,this.g,this.b,this.opacity]+")"},$=function(a,b,d){if(null==b&&e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&e(a,string)){var f=c.getRGB(a);a=f.r,b=f.g,d=f.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},_=function(a,b,d,f){a=D.round(255*a),b=D.round(255*b),d=D.round(255*d);var g={r:a,g:b,b:d,opacity:e(f,"finite")?f:1,hex:c.rgb(a,b,d),toString:Z};return e(f,"finite")&&(g.opacity=f),g};c.color=function(a){var b;return e(a,"object")&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):e(a,"object")&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):(e(a,"string")&&(a=c.getRGB(a)),e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&!("error"in a)?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:"none"},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1,a.error=1)),a.toString=Z,a},c.hsb2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,d=a.o,a=a.h),a*=360;var f,g,h,i,j;return a=a%360/60,j=c*b,i=j*(1-G(a%2-1)),f=g=h=c-j,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.hsl2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var f,g,h,i,j;return a=a%360/60,j=2*b*(.5>c?c:1-c),i=j*(1-G(a%2-1)),f=g=h=c-j/2,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.rgb2hsb=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=E(a,b,c),g=f-F(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:X}},c.rgb2hsl=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=E(a,b,c),h=F(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:Y}},c.parsePathString=function(a){if(!a)return null;var b=c.path(a);if(b.arr)return c.path.clone(b.arr);var d={a:7,c:6,o:2,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,u:3,z:0},f=[];return e(a,"array")&&e(a[0],"array")&&(f=c.path.clone(a)),f.length||A(a).replace(N,function(a,b,c){var e=[],g=b.toLowerCase();if(c.replace(P,function(a,b){b&&e.push(+b)}),"m"==g&&e.length>2&&(f.push([b].concat(e.splice(0,2))),g="l",b="m"==b?"l":"L"),"o"==g&&1==e.length&&f.push([b,e[0]]),"r"==g)f.push([b].concat(e));else for(;e.length>=d[g]&&(f.push([b].concat(e.splice(0,d[g]))),d[g]););}),f.toString=c.path.toString,b.arr=c.path.clone(f),f};var ab=c.parseTransformString=function(a){if(!a)return null;var b=[];return e(a,"array")&&e(a[0],"array")&&(b=c.path.clone(a)),b.length||A(a).replace(O,function(a,c,d){{var e=[];c.toLowerCase()}d.replace(P,function(a,b){b&&e.push(+b)}),b.push([c].concat(e))}),b.toString=c.path.toString,b};c._.svgTransform2string=m,c._.rgTransform=/^[a-z][\s]*-?\.?\d/i,c._.transform2matrix=n,c._unit2px=q;y.doc.contains||y.doc.compareDocumentPosition?function(a,b){var c=9==a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a==d||!(!d||1!=d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b;)if(b=b.parentNode,b==a)return!0;return!1};c._.getSomeDefs=o,c._.getSomeSVG=p,c.select=function(a){return a=A(a).replace(/([^\\]):/g,"$1\\:"),w(y.doc.querySelector(a))},c.selectAll=function(a){for(var b=y.doc.querySelectorAll(a),d=(c.set||Array)(),e=0;e<b.length;e++)d.push(w(b[e]));return d},setInterval(function(){for(var a in V)if(V[z](a)){var b=V[a],c=b.node;("svg"!=b.type&&!c.ownerSVGElement||"svg"==b.type&&(!c.parentNode||"ownerSVGElement"in c.parentNode&&!c.ownerSVGElement))&&delete V[a]}},1e4),s.prototype.attr=function(a,c){var d=this,f=d.node;if(!a){if(1!=f.nodeType)return{text:f.nodeValue};for(var g=f.attributes,h={},i=0,j=g.length;j>i;i++)h[g[i].nodeName]=g[i].nodeValue;return h}if(e(a,"string")){if(!(arguments.length>1))return b("snap.util.getattr."+a,d).firstDefined();var k={};k[a]=c,a=k}for(var l in a)a[z](l)&&b("snap.util.attr."+l,d,a[l]);return d},c.parse=function(a){var b=y.doc.createDocumentFragment(),c=!0,d=y.doc.createElement("div");if(a=A(a),a.match(/^\s*<\s*svg(?:\s|>)/)||(a="<svg>"+a+"</svg>",c=!1),d.innerHTML=a,a=d.getElementsByTagName("svg")[0])if(c)b=a;else for(;a.firstChild;)b.appendChild(a.firstChild);return new t(b)},c.fragment=function(){for(var a=Array.prototype.slice.call(arguments,0),b=y.doc.createDocumentFragment(),d=0,e=a.length;e>d;d++){var f=a[d];f.node&&f.node.nodeType&&b.appendChild(f.node),f.nodeType&&b.appendChild(f),"string"==typeof f&&b.appendChild(c.parse(f).node)}return new t(b)},c._.make=u,c._.wrap=w,v.prototype.el=function(a,b){var c=u(a,this.node);return b&&c.attr(b),c},s.prototype.children=function(){for(var a=[],b=this.node.childNodes,d=0,e=b.length;e>d;d++)a[d]=c(b[d]);return a},s.prototype.toJSON=function(){var a=[];return x([this],a),a[0]},b.on("snap.util.getattr",function(){var a=b.nt();a=a.substring(a.lastIndexOf(".")+1);var c=a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});return bb[z](c)?this.node.ownerDocument.defaultView.getComputedStyle(this.node,null).getPropertyValue(c):d(this.node,a)});var bb={"alignment-baseline":0,"baseline-shift":0,clip:0,"clip-path":0,"clip-rule":0,color:0,"color-interpolation":0,"color-interpolation-filters":0,"color-profile":0,"color-rendering":0,cursor:0,direction:0,display:0,"dominant-baseline":0,"enable-background":0,fill:0,"fill-opacity":0,"fill-rule":0,filter:0,"flood-color":0,"flood-opacity":0,font:0,"font-family":0,"font-size":0,"font-size-adjust":0,"font-stretch":0,"font-style":0,"font-variant":0,"font-weight":0,"glyph-orientation-horizontal":0,"glyph-orientation-vertical":0,"image-rendering":0,kerning:0,"letter-spacing":0,"lighting-color":0,marker:0,"marker-end":0,"marker-mid":0,"marker-start":0,mask:0,opacity:0,overflow:0,"pointer-events":0,"shape-rendering":0,"stop-color":0,"stop-opacity":0,stroke:0,"stroke-dasharray":0,"stroke-dashoffset":0,"stroke-linecap":0,"stroke-linejoin":0,"stroke-miterlimit":0,"stroke-opacity":0,"stroke-width":0,"text-anchor":0,"text-decoration":0,"text-rendering":0,"unicode-bidi":0,visibility:0,"word-spacing":0,"writing-mode":0};b.on("snap.util.attr",function(a){var c=b.nt(),e={};c=c.substring(c.lastIndexOf(".")+1),e[c]=a;var f=c.replace(/-(\w)/gi,function(a,b){return b.toUpperCase()}),g=c.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});bb[z](g)?this.node.style[f]=null==a?I:a:d(this.node,e)}),function(){}(v.prototype),c.ajax=function(a,c,d,f){var g=new XMLHttpRequest,h=S();if(g){if(e(c,"function"))f=d,d=c,c=null;else if(e(c,"object")){var i=[];for(var j in c)c.hasOwnProperty(j)&&i.push(encodeURIComponent(j)+"="+encodeURIComponent(c[j]));c=i.join("&")}return g.open(c?"POST":"GET",a,!0),c&&(g.setRequestHeader("X-Requested-With","XMLHttpRequest"),g.setRequestHeader("Content-type","application/x-www-form-urlencoded")),d&&(b.once("snap.ajax."+h+".0",d),b.once("snap.ajax."+h+".200",d),b.once("snap.ajax."+h+".304",d)),g.onreadystatechange=function(){4==g.readyState&&b("snap.ajax."+h+"."+g.status,f,g)},4==g.readyState?g:(g.send(c),g)}},c.load=function(a,b,d){c.ajax(a,function(a){var e=c.parse(a.responseText);d?b.call(d,e):b(e)})};var cb=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,h=e.clientLeft||d.clientLeft||0,i=b.top+(g.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(g.win.pageXOffset||e.scrollLeft||d.scrollLeft)-h;return{y:i,x:j}};return c.getElementByPoint=function(a,b){var c=this,d=(c.canvas,y.doc.elementFromPoint(a,b));if(y.win.opera&&"svg"==d.tagName){var e=cb(d),f=d.createSVGRect();f.x=a-e.x,f.y=b-e.y,f.width=f.height=1;var g=d.getIntersectionList(f,null);g.length&&(d=g[g.length-1])}return d?w(d):null},c.plugin=function(a){a(c,s,v,y,t)},y.win.Snap=c,c}(a||this);return d.plugin(function(d,e,f,g,h){function i(a,b){if(null==b){var c=!0;if(b=a.node.getAttribute("linearGradient"==a.type||"radialGradient"==a.type?"gradientTransform":"pattern"==a.type?"patternTransform":"transform"),!b)return new d.Matrix;b=d._.svgTransform2string(b)}else b=d._.rgTransform.test(b)?o(b).replace(/\.{3}|\u2026/g,a._.transform||""):d._.svgTransform2string(b),n(b,"array")&&(b=d.path?d.path.toString.call(b):o(b)),a._.transform=b;var e=d._.transform2matrix(b,a.getBBox(1));return c?e:void(a.matrix=e)}function j(a){function b(a,b){var c=q(a.node,b);c=c&&c.match(f),c=c&&c[2],c&&"#"==c.charAt()&&(c=c.substring(1),c&&(h[c]=(h[c]||[]).concat(function(c){var d={};d[b]=URL(c),q(a.node,d)})))}function c(a){var b=q(a.node,"xlink:href");b&&"#"==b.charAt()&&(b=b.substring(1),b&&(h[b]=(h[b]||[]).concat(function(b){a.attr("xlink:href","#"+b)})))}for(var d,e=a.selectAll("*"),f=/^\s*url\(("|'|)(.*)\1\)\s*$/,g=[],h={},i=0,j=e.length;j>i;i++){d=e[i],b(d,"fill"),b(d,"stroke"),b(d,"filter"),b(d,"mask"),b(d,"clip-path"),c(d);var k=q(d.node,"id");k&&(q(d.node,{id:d.id}),g.push({old:k,id:d.id}))}for(i=0,j=g.length;j>i;i++){var l=h[g[i].old];if(l)for(var m=0,n=l.length;n>m;m++)l[m](g[i].id)}}function k(a,b,c){return function(d){var e=d.slice(a,b);return 1==e.length&&(e=e[0]),c?c(e):e}}function l(a){return function(){var b=a?"<"+this.type:"",c=this.node.attributes,d=this.node.childNodes;if(a)for(var e=0,f=c.length;f>e;e++)b+=" "+c[e].name+'="'+c[e].value.replace(/"/g,'\\"')+'"';if(d.length){for(a&&(b+=">"),e=0,f=d.length;f>e;e++)3==d[e].nodeType?b+=d[e].nodeValue:1==d[e].nodeType&&(b+=u(d[e]).toString());a&&(b+="</"+this.type+">")}else a&&(b+="/>");return b}}var m=e.prototype,n=d.is,o=String,p=d._unit2px,q=d._.$,r=d._.make,s=d._.getSomeDefs,t="hasOwnProperty",u=d._.wrap;m.getBBox=function(a){if(!d.Matrix||!d.path)return this.node.getBBox();var b=this,c=new d.Matrix;if(b.removed)return d._.box();for(;"use"==b.type;)if(a||(c=c.add(b.transform().localMatrix.translate(b.attr("x")||0,b.attr("y")||0))),b.original)b=b.original;else{var e=b.attr("xlink:href");b=b.original=b.node.ownerDocument.getElementById(e.substring(e.indexOf("#")+1))}var f=b._,g=d.path.get[b.type]||d.path.get.deflt;try{return a?(f.bboxwt=g?d.path.getBBox(b.realPath=g(b)):d._.box(b.node.getBBox()),d._.box(f.bboxwt)):(b.realPath=g(b),b.matrix=b.transform().localMatrix,f.bbox=d.path.getBBox(d.path.map(b.realPath,c.add(b.matrix))),d._.box(f.bbox))}catch(h){return d._.box()}};var v=function(){return this.string};m.transform=function(a){var b=this._;if(null==a){for(var c,e=this,f=new d.Matrix(this.node.getCTM()),g=i(this),h=[g],j=new d.Matrix,k=g.toTransformString(),l=o(g)==o(this.matrix)?o(b.transform):k;"svg"!=e.type&&(e=e.parent());)h.push(i(e));for(c=h.length;c--;)j.add(h[c]);return{string:l,globalMatrix:f,totalMatrix:j,localMatrix:g,diffMatrix:f.clone().add(g.invert()),global:f.toTransformString(),total:j.toTransformString(),local:k,toString:v}}return a instanceof d.Matrix?(this.matrix=a,this._.transform=a.toTransformString()):i(this,a),this.node&&("linearGradient"==this.type||"radialGradient"==this.type?q(this.node,{gradientTransform:this.matrix}):"pattern"==this.type?q(this.node,{patternTransform:this.matrix}):q(this.node,{transform:this.matrix})),this},m.parent=function(){return u(this.node.parentNode)},m.append=m.add=function(a){if(a){if("set"==a.type){var b=this;return a.forEach(function(a){b.add(a)}),this}a=u(a),this.node.appendChild(a.node),a.paper=this.paper}return this},m.appendTo=function(a){return a&&(a=u(a),a.append(this)),this},m.prepend=function(a){if(a){if("set"==a.type){var b,c=this;return a.forEach(function(a){b?b.after(a):c.prepend(a),b=a}),this}a=u(a);var d=a.parent();this.node.insertBefore(a.node,this.node.firstChild),this.add&&this.add(),a.paper=this.paper,this.parent()&&this.parent().add(),d&&d.add()}return this},m.prependTo=function(a){return a=u(a),a.prepend(this),this},m.before=function(a){if("set"==a.type){var b=this;return a.forEach(function(a){var c=a.parent();b.node.parentNode.insertBefore(a.node,b.node),c&&c.add()}),this.parent().add(),this}a=u(a);var c=a.parent();return this.node.parentNode.insertBefore(a.node,this.node),this.parent()&&this.parent().add(),c&&c.add(),a.paper=this.paper,this},m.after=function(a){a=u(a);var b=a.parent();return this.node.nextSibling?this.node.parentNode.insertBefore(a.node,this.node.nextSibling):this.node.parentNode.appendChild(a.node),this.parent()&&this.parent().add(),b&&b.add(),a.paper=this.paper,this},m.insertBefore=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.insertAfter=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node.nextSibling),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.remove=function(){var a=this.parent();return this.node.parentNode&&this.node.parentNode.removeChild(this.node),delete this.paper,this.removed=!0,a&&a.add(),this},m.select=function(a){return u(this.node.querySelector(a))},m.selectAll=function(a){for(var b=this.node.querySelectorAll(a),c=(d.set||Array)(),e=0;e<b.length;e++)c.push(u(b[e]));return c},m.asPX=function(a,b){return null==b&&(b=this.attr(a)),+p(this,a,b)},m.use=function(){var a,b=this.node.id;return b||(b=this.id,q(this.node,{id:b})),a="linearGradient"==this.type||"radialGradient"==this.type||"pattern"==this.type?r(this.type,this.node.parentNode):r("use",this.node.parentNode),q(a.node,{"xlink:href":"#"+b}),a.original=this,a},m.clone=function(){var a=u(this.node.cloneNode(!0));return q(a.node,"id")&&q(a.node,{id:a.id}),j(a),a.insertAfter(this),a},m.toDefs=function(){var a=s(this);return a.appendChild(this.node),this},m.pattern=m.toPattern=function(a,b,c,d){var e=r("pattern",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,a=a.x),q(e.node,{x:a,y:b,width:c,height:d,patternUnits:"userSpaceOnUse",id:e.id,viewBox:[a,b,c,d].join(" ")}),e.node.appendChild(this.node),e},m.marker=function(a,b,c,d,e,f){var g=r("marker",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,e=a.refX||a.cx,f=a.refY||a.cy,a=a.x),q(g.node,{viewBox:[a,b,c,d].join(" "),markerWidth:c,markerHeight:d,orient:"auto",refX:e||0,refY:f||0,id:g.id}),g.node.appendChild(this.node),g};var w=function(a,b,d,e){"function"!=typeof d||d.length||(e=d,d=c.linear),this.attr=a,this.dur=b,d&&(this.easing=d),e&&(this.callback=e)};d._.Animation=w,d.animation=function(a,b,c,d){return new w(a,b,c,d)},m.inAnim=function(){var a=this,b=[];for(var c in a.anims)a.anims[t](c)&&!function(a){b.push({anim:new w(a._attrs,a.dur,a.easing,a._callback),mina:a,curStatus:a.status(),status:function(b){return a.status(b)},stop:function(){a.stop()}})}(a.anims[c]);return b},d.animate=function(a,d,e,f,g,h){"function"!=typeof g||g.length||(h=g,g=c.linear);var i=c.time(),j=c(a,d,i,i+f,c.time,e,g);return h&&b.once("mina.finish."+j.id,h),j},m.stop=function(){for(var a=this.inAnim(),b=0,c=a.length;c>b;b++)a[b].stop();return this},m.animate=function(a,d,e,f){"function"!=typeof e||e.length||(f=e,e=c.linear),a instanceof w&&(f=a.callback,e=a.easing,d=a.dur,a=a.attr);var g,h,i,j,l=[],m=[],p={},q=this;for(var r in a)if(a[t](r)){q.equal?(j=q.equal(r,o(a[r])),g=j.from,h=j.to,i=j.f):(g=+q.attr(r),h=+a[r]);var s=n(g,"array")?g.length:1;p[r]=k(l.length,l.length+s,i),l=l.concat(g),m=m.concat(h)}var u=c.time(),v=c(l,m,u,u+d,c.time,function(a){var b={};for(var c in p)p[t](c)&&(b[c]=p[c](a));q.attr(b)},e);return q.anims[v.id]=v,v._attrs=a,v._callback=f,b("snap.animcreated."+q.id,v),b.once("mina.finish."+v.id,function(){delete q.anims[v.id],f&&f.call(q)}),b.once("mina.stop."+v.id,function(){delete q.anims[v.id]}),q};var x={};m.data=function(a,c){var e=x[this.id]=x[this.id]||{};if(0==arguments.length)return b("snap.data.get."+this.id,this,e,null),e; +if(1==arguments.length){if(d.is(a,"object")){for(var f in a)a[t](f)&&this.data(f,a[f]);return this}return b("snap.data.get."+this.id,this,e[a],a),e[a]}return e[a]=c,b("snap.data.set."+this.id,this,c,a),this},m.removeData=function(a){return null==a?x[this.id]={}:x[this.id]&&delete x[this.id][a],this},m.outerSVG=m.toString=l(1),m.innerSVG=l(),m.toDataURL=function(){if(a&&a.btoa){var b=this.getBBox(),c=d.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>',{x:+b.x.toFixed(3),y:+b.y.toFixed(3),width:+b.width.toFixed(3),height:+b.height.toFixed(3),contents:this.outerSVG()});return"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(c)))}},h.prototype.select=m.select,h.prototype.selectAll=m.selectAll}),d.plugin(function(a){function b(a,b,d,e,f,g){return null==b&&"[object SVGMatrix]"==c.call(a)?(this.a=a.a,this.b=a.b,this.c=a.c,this.d=a.d,this.e=a.e,void(this.f=a.f)):void(null!=a?(this.a=+a,this.b=+b,this.c=+d,this.d=+e,this.e=+f,this.f=+g):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0))}var c=Object.prototype.toString,d=String,e=Math,f="";!function(c){function g(a){return a[0]*a[0]+a[1]*a[1]}function h(a){var b=e.sqrt(g(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}c.add=function(a,c,d,e,f,g){var h,i,j,k,l=[[],[],[]],m=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],n=[[a,d,f],[c,e,g],[0,0,1]];for(a&&a instanceof b&&(n=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),h=0;3>h;h++)for(i=0;3>i;i++){for(k=0,j=0;3>j;j++)k+=m[h][j]*n[j][i];l[h][i]=k}return this.a=l[0][0],this.b=l[1][0],this.c=l[0][1],this.d=l[1][1],this.e=l[0][2],this.f=l[1][2],this},c.invert=function(){var a=this,c=a.a*a.d-a.b*a.c;return new b(a.d/c,-a.b/c,-a.c/c,a.a/c,(a.c*a.f-a.d*a.e)/c,(a.b*a.e-a.a*a.f)/c)},c.clone=function(){return new b(this.a,this.b,this.c,this.d,this.e,this.f)},c.translate=function(a,b){return this.add(1,0,0,1,a,b)},c.scale=function(a,b,c,d){return null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d),this},c.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var f=+e.cos(b).toFixed(9),g=+e.sin(b).toFixed(9);return this.add(f,g,-g,f,c,d),this.add(1,0,0,1,-c,-d)},c.x=function(a,b){return a*this.a+b*this.c+this.e},c.y=function(a,b){return a*this.b+b*this.d+this.f},c.get=function(a){return+this[d.fromCharCode(97+a)].toFixed(4)},c.toString=function(){return"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")"},c.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},c.determinant=function(){return this.a*this.d-this.b*this.c},c.split=function(){var b={};b.dx=this.e,b.dy=this.f;var c=[[this.a,this.c],[this.b,this.d]];b.scalex=e.sqrt(g(c[0])),h(c[0]),b.shear=c[0][0]*c[1][0]+c[0][1]*c[1][1],c[1]=[c[1][0]-c[0][0]*b.shear,c[1][1]-c[0][1]*b.shear],b.scaley=e.sqrt(g(c[1])),h(c[1]),b.shear/=b.scaley,this.determinant()<0&&(b.scalex=-b.scalex);var d=-c[0][1],f=c[1][1];return 0>f?(b.rotate=a.deg(e.acos(f)),0>d&&(b.rotate=360-b.rotate)):b.rotate=a.deg(e.asin(d)),b.isSimple=!(+b.shear.toFixed(9)||b.scalex.toFixed(9)!=b.scaley.toFixed(9)&&b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate,b},c.toTransformString=function(a){var b=a||this.split();return+b.shear.toFixed(9)?"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]:(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[+b.dx.toFixed(4),+b.dy.toFixed(4)]:f)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:f)+(b.rotate?"r"+[+b.rotate.toFixed(4),0,0]:f))}}(b.prototype),a.Matrix=b,a.matrix=function(a,c,d,e,f,g){return new b(a,c,d,e,f,g)}}),d.plugin(function(a,c,d,e,f){function g(d){return function(e){if(b.stop(),e instanceof f&&1==e.node.childNodes.length&&("radialGradient"==e.node.firstChild.tagName||"linearGradient"==e.node.firstChild.tagName||"pattern"==e.node.firstChild.tagName)&&(e=e.node.firstChild,n(this).appendChild(e),e=l(e)),e instanceof c)if("radialGradient"==e.type||"linearGradient"==e.type||"pattern"==e.type){e.node.id||p(e.node,{id:e.id});var g=q(e.node.id)}else g=e.attr(d);else if(g=a.color(e),g.error){var h=a(n(this).ownerSVGElement).gradient(e);h?(h.node.id||p(h.node,{id:h.id}),g=q(h.node.id)):g=e}else g=r(g);var i={};i[d]=g,p(this.node,i),this.node.style[d]=t}}function h(a){b.stop(),a==+a&&(a+="px"),this.node.style.fontSize=a}function i(a){for(var b=[],c=a.childNodes,d=0,e=c.length;e>d;d++){var f=c[d];3==f.nodeType&&b.push(f.nodeValue),"tspan"==f.tagName&&b.push(1==f.childNodes.length&&3==f.firstChild.nodeType?f.firstChild.nodeValue:i(f))}return b}function j(){return b.stop(),this.node.style.fontSize}var k=a._.make,l=a._.wrap,m=a.is,n=a._.getSomeDefs,o=/^url\(#?([^)]+)\)$/,p=a._.$,q=a.url,r=String,s=a._.separator,t="";b.on("snap.util.attr.mask",function(a){if(a instanceof c||a instanceof f){if(b.stop(),a instanceof f&&1==a.node.childNodes.length&&(a=a.node.firstChild,n(this).appendChild(a),a=l(a)),"mask"==a.type)var d=a;else d=k("mask",n(this)),d.node.appendChild(a.node);!d.node.id&&p(d.node,{id:d.id}),p(this.node,{mask:q(d.id)})}}),function(a){b.on("snap.util.attr.clip",a),b.on("snap.util.attr.clip-path",a),b.on("snap.util.attr.clipPath",a)}(function(a){if(a instanceof c||a instanceof f){if(b.stop(),"clipPath"==a.type)var d=a;else d=k("clipPath",n(this)),d.node.appendChild(a.node),!d.node.id&&p(d.node,{id:d.id});p(this.node,{"clip-path":q(d.node.id||d.id)})}}),b.on("snap.util.attr.fill",g("fill")),b.on("snap.util.attr.stroke",g("stroke"));var u=/^([lr])(?:\(([^)]*)\))?(.*)$/i;b.on("snap.util.grad.parse",function(a){a=r(a);var b=a.match(u);if(!b)return null;var c=b[1],d=b[2],e=b[3];return d=d.split(/\s*,\s*/).map(function(a){return+a==a?+a:a}),1==d.length&&0==d[0]&&(d=[]),e=e.split("-"),e=e.map(function(a){a=a.split(":");var b={color:a[0]};return a[1]&&(b.offset=parseFloat(a[1])),b}),{type:c,params:d,stops:e}}),b.on("snap.util.attr.d",function(c){b.stop(),m(c,"array")&&m(c[0],"array")&&(c=a.path.toString.call(c)),c=r(c),c.match(/[ruo]/i)&&(c=a.path.toAbsolute(c)),p(this.node,{d:c})})(-1),b.on("snap.util.attr.#text",function(a){b.stop(),a=r(a);for(var c=e.doc.createTextNode(a);this.node.firstChild;)this.node.removeChild(this.node.firstChild);this.node.appendChild(c)})(-1),b.on("snap.util.attr.path",function(a){b.stop(),this.attr({d:a})})(-1),b.on("snap.util.attr.class",function(a){b.stop(),this.node.className.baseVal=a})(-1),b.on("snap.util.attr.viewBox",function(a){var c;c=m(a,"object")&&"x"in a?[a.x,a.y,a.width,a.height].join(" "):m(a,"array")?a.join(" "):a,p(this.node,{viewBox:c}),b.stop()})(-1),b.on("snap.util.attr.transform",function(a){this.transform(a),b.stop()})(-1),b.on("snap.util.attr.r",function(a){"rect"==this.type&&(b.stop(),p(this.node,{rx:a,ry:a}))})(-1),b.on("snap.util.attr.textpath",function(a){if(b.stop(),"text"==this.type){var d,e,f;if(!a&&this.textPath){for(e=this.textPath;e.node.firstChild;)this.node.appendChild(e.node.firstChild);return e.remove(),void delete this.textPath}if(m(a,"string")){var g=n(this),h=l(g.parentNode).path(a);g.appendChild(h.node),d=h.id,h.attr({id:d})}else a=l(a),a instanceof c&&(d=a.attr("id"),d||(d=a.id,a.attr({id:d})));if(d)if(e=this.textPath,f=this.node,e)e.attr({"xlink:href":"#"+d});else{for(e=p("textPath",{"xlink:href":"#"+d});f.firstChild;)e.appendChild(f.firstChild);f.appendChild(e),this.textPath=l(e)}}})(-1),b.on("snap.util.attr.text",function(a){if("text"==this.type){for(var c=this.node,d=function(a){var b=p("tspan");if(m(a,"array"))for(var c=0;c<a.length;c++)b.appendChild(d(a[c]));else b.appendChild(e.doc.createTextNode(a));return b.normalize&&b.normalize(),b};c.firstChild;)c.removeChild(c.firstChild);for(var f=d(a);f.firstChild;)c.appendChild(f.firstChild)}b.stop()})(-1),b.on("snap.util.attr.fontSize",h)(-1),b.on("snap.util.attr.font-size",h)(-1),b.on("snap.util.getattr.transform",function(){return b.stop(),this.transform()})(-1),b.on("snap.util.getattr.textpath",function(){return b.stop(),this.textPath})(-1),function(){function c(c){return function(){b.stop();var d=e.doc.defaultView.getComputedStyle(this.node,null).getPropertyValue("marker-"+c);return"none"==d?d:a(e.doc.getElementById(d.match(o)[1]))}}function d(a){return function(c){b.stop();var d="marker"+a.charAt(0).toUpperCase()+a.substring(1);if(""==c||!c)return void(this.node.style[d]="none");if("marker"==c.type){var e=c.node.id;return e||p(c.node,{id:c.id}),void(this.node.style[d]=q(e))}}}b.on("snap.util.getattr.marker-end",c("end"))(-1),b.on("snap.util.getattr.markerEnd",c("end"))(-1),b.on("snap.util.getattr.marker-start",c("start"))(-1),b.on("snap.util.getattr.markerStart",c("start"))(-1),b.on("snap.util.getattr.marker-mid",c("mid"))(-1),b.on("snap.util.getattr.markerMid",c("mid"))(-1),b.on("snap.util.attr.marker-end",d("end"))(-1),b.on("snap.util.attr.markerEnd",d("end"))(-1),b.on("snap.util.attr.marker-start",d("start"))(-1),b.on("snap.util.attr.markerStart",d("start"))(-1),b.on("snap.util.attr.marker-mid",d("mid"))(-1),b.on("snap.util.attr.markerMid",d("mid"))(-1)}(),b.on("snap.util.getattr.r",function(){return"rect"==this.type&&p(this.node,"rx")==p(this.node,"ry")?(b.stop(),p(this.node,"rx")):void 0})(-1),b.on("snap.util.getattr.text",function(){if("text"==this.type||"tspan"==this.type){b.stop();var a=i(this.node);return 1==a.length?a[0]:a}})(-1),b.on("snap.util.getattr.#text",function(){return this.node.textContent})(-1),b.on("snap.util.getattr.viewBox",function(){b.stop();var c=p(this.node,"viewBox");return c?(c=c.split(s),a._.box(+c[0],+c[1],+c[2],+c[3])):void 0})(-1),b.on("snap.util.getattr.points",function(){var a=p(this.node,"points");return b.stop(),a?a.split(s):void 0})(-1),b.on("snap.util.getattr.path",function(){var a=p(this.node,"d");return b.stop(),a})(-1),b.on("snap.util.getattr.class",function(){return this.node.className.baseVal})(-1),b.on("snap.util.getattr.fontSize",j)(-1),b.on("snap.util.getattr.font-size",j)(-1)}),d.plugin(function(a,b){var c=/\S+/g,d=String,e=b.prototype;e.addClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(h.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e||k.push(f);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.removeClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(k.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e&&k.splice(e,1);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.hasClass=function(a){var b=this.node,d=b.className.baseVal,e=d.match(c)||[];return!!~e.indexOf(a)},e.toggleClass=function(a,b){if(null!=b)return b?this.addClass(a):this.removeClass(a);var d,e,f,g,h=(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];for(d=0;f=h[d++];)e=k.indexOf(f),~e?k.splice(e,1):k.push(f);return g=k.join(" "),j!=g&&(i.className.baseVal=g),this}}),d.plugin(function(){function a(a){return a}function c(a){return function(b){return+b.toFixed(3)+a}}var d={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"/":function(a,b){return a/b},"*":function(a,b){return a*b}},e=String,f=/[a-z]+$/i,g=/^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;b.on("snap.util.attr",function(a){var c=e(a).match(g);if(c){var h=b.nt(),i=h.substring(h.lastIndexOf(".")+1),j=this.attr(i),k={};b.stop();var l=c[3]||"",m=j.match(f),n=d[c[1]];if(m&&m==l?a=n(parseFloat(j),+c[2]):(j=this.asPX(i),a=n(this.asPX(i),this.asPX(i,c[2]+l))),isNaN(j)||isNaN(a))return;k[i]=a,this.attr(k)}})(-10),b.on("snap.util.equal",function(h,i){var j=e(this.attr(h)||""),k=e(i).match(g);if(k){b.stop();var l=k[3]||"",m=j.match(f),n=d[k[1]];return m&&m==l?{from:parseFloat(j),to:n(parseFloat(j),+k[2]),f:c(m)}:(j=this.asPX(h),{from:j,to:n(j,this.asPX(h,k[2]+l)),f:a})}})(-10)}),d.plugin(function(c,d,e,f){var g=e.prototype,h=c.is;g.rect=function(a,b,c,d,e,f){var g;return null==f&&(f=e),h(a,"object")&&"[object Object]"==a?g=a:null!=a&&(g={x:a,y:b,width:c,height:d},null!=e&&(g.rx=e,g.ry=f)),this.el("rect",g)},g.circle=function(a,b,c){var d;return h(a,"object")&&"[object Object]"==a?d=a:null!=a&&(d={cx:a,cy:b,r:c}),this.el("circle",d)};var i=function(){function a(){this.parentNode.removeChild(this)}return function(b,c){var d=f.doc.createElement("img"),e=f.doc.body;d.style.cssText="position:absolute;left:-9999em;top:-9999em",d.onload=function(){c.call(d),d.onload=d.onerror=null,e.removeChild(d)},d.onerror=a,e.appendChild(d),d.src=b}}();g.image=function(a,b,d,e,f){var g=this.el("image");if(h(a,"object")&&"src"in a)g.attr(a);else if(null!=a){var j={"xlink:href":a,preserveAspectRatio:"none"};null!=b&&null!=d&&(j.x=b,j.y=d),null!=e&&null!=f?(j.width=e,j.height=f):i(a,function(){c._.$(g.node,{width:this.offsetWidth,height:this.offsetHeight})}),c._.$(g.node,j)}return g},g.ellipse=function(a,b,c,d){var e;return h(a,"object")&&"[object Object]"==a?e=a:null!=a&&(e={cx:a,cy:b,rx:c,ry:d}),this.el("ellipse",e)},g.path=function(a){var b;return h(a,"object")&&!h(a,"array")?b=a:a&&(b={d:a}),this.el("path",b)},g.group=g.g=function(a){var b=this.el("g");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.svg=function(a,b,c,d,e,f,g,i){var j={};return h(a,"object")&&null==b?j=a:(null!=a&&(j.x=a),null!=b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),null!=e&&null!=f&&null!=g&&null!=i&&(j.viewBox=[e,f,g,i])),this.el("svg",j)},g.mask=function(a){var b=this.el("mask");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.ptrn=function(a,b,c,d,e,f,g,i){if(h(a,"object"))var j=a;else j={patternUnits:"userSpaceOnUse"},a&&(j.x=a),b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),j.viewBox=null!=e&&null!=f&&null!=g&&null!=i?[e,f,g,i]:[a||0,b||0,c||0,d||0];return this.el("pattern",j)},g.use=function(a){return null!=a?(a instanceof d&&(a.attr("id")||a.attr({id:c._.id(a)}),a=a.attr("id")),"#"==String(a).charAt()&&(a=a.substring(1)),this.el("use",{"xlink:href":"#"+a})):d.prototype.use.call(this)},g.symbol=function(a,b,c,d){var e={};return null!=a&&null!=b&&null!=c&&null!=d&&(e.viewBox=[a,b,c,d]),this.el("symbol",e)},g.text=function(a,b,c){var d={};return h(a,"object")?d=a:null!=a&&(d={x:a,y:b,text:c||""}),this.el("text",d)},g.line=function(a,b,c,d){var e={};return h(a,"object")?e=a:null!=a&&(e={x1:a,x2:c,y1:b,y2:d}),this.el("line",e)},g.polyline=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polyline",b)},g.polygon=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polygon",b)},function(){function d(){return this.selectAll("stop")}function e(a,b){var d=k("stop"),e={offset:+b+"%"};return a=c.color(a),e["stop-color"]=a.hex,a.opacity<1&&(e["stop-opacity"]=a.opacity),k(d,e),this.node.appendChild(d),this}function f(){if("linearGradient"==this.type){var a=k(this.node,"x1")||0,b=k(this.node,"x2")||1,d=k(this.node,"y1")||0,e=k(this.node,"y2")||0;return c._.box(a,d,math.abs(b-a),math.abs(e-d))}var f=this.node.cx||.5,g=this.node.cy||.5,h=this.node.r||0;return c._.box(f-h,g-h,2*h,2*h)}function h(a,c){function d(a,b){for(var c=(b-l)/(a-m),d=m;a>d;d++)g[d].offset=+(+l+c*(d-m)).toFixed(2);m=a,l=b}var e,f=b("snap.util.grad.parse",null,c).firstDefined();if(!f)return null;f.params.unshift(a),e="l"==f.type.toLowerCase()?i.apply(0,f.params):j.apply(0,f.params),f.type!=f.type.toLowerCase()&&k(e.node,{gradientUnits:"userSpaceOnUse"});var g=f.stops,h=g.length,l=0,m=0;h--;for(var n=0;h>n;n++)"offset"in g[n]&&d(n,g[n].offset);for(g[h].offset=g[h].offset||100,d(h,g[h].offset),n=0;h>=n;n++){var o=g[n];e.addStop(o.color,o.offset)}return e}function i(a,b,g,h,i){var j=c._.make("linearGradient",a);return j.stops=d,j.addStop=e,j.getBBox=f,null!=b&&k(j.node,{x1:b,y1:g,x2:h,y2:i}),j}function j(a,b,g,h,i,j){var l=c._.make("radialGradient",a);return l.stops=d,l.addStop=e,l.getBBox=f,null!=b&&k(l.node,{cx:b,cy:g,r:h}),null!=i&&null!=j&&k(l.node,{fx:i,fy:j}),l}var k=c._.$;g.gradient=function(a){return h(this.defs,a)},g.gradientLinear=function(a,b,c,d){return i(this.defs,a,b,c,d)},g.gradientRadial=function(a,b,c,d,e){return j(this.defs,a,b,c,d,e)},g.toString=function(){var a,b=this.node.ownerDocument,d=b.createDocumentFragment(),e=b.createElement("div"),f=this.node.cloneNode(!0);return d.appendChild(e),e.appendChild(f),c._.$(f,{xmlns:"http://www.w3.org/2000/svg"}),a=e.innerHTML,d.removeChild(d.firstChild),a},g.toDataURL=function(){return a&&a.btoa?"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(this))):void 0},g.clear=function(){for(var a,b=this.node.firstChild;b;)a=b.nextSibling,"defs"!=b.tagName?b.parentNode.removeChild(b):g.clear.call({node:b}),b=a}}()}),d.plugin(function(a,b){function c(a){var b=c.ps=c.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[K](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]}function d(a,b,c,d){return null==a&&(a=b=c=d=0),null==b&&(b=a.y,c=a.width,d=a.height,a=a.x),{x:a,y:b,width:c,w:c,height:d,h:d,x2:a+c,y2:b+d,cx:a+c/2,cy:b+d/2,r1:N.min(c,d)/2,r2:N.max(c,d)/2,r0:N.sqrt(c*c+d*d)/2,path:w(a,b,c,d),vb:[a,b,c,d].join(" ")}}function e(){return this.join(",").replace(L,"$1")}function f(a){var b=J(a);return b.toString=e,b}function g(a,b,c,d,e,f,g,h,j){return null==j?n(a,b,c,d,e,f,g,h):i(a,b,c,d,e,f,g,h,o(a,b,c,d,e,f,g,h,j))}function h(c,d){function e(a){return+(+a).toFixed(3)}return a._.cacher(function(a,f,h){a instanceof b&&(a=a.attr("d")),a=E(a);for(var j,k,l,m,n,o="",p={},q=0,r=0,s=a.length;s>r;r++){if(l=a[r],"M"==l[0])j=+l[1],k=+l[2];else{if(m=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6]),q+m>f){if(d&&!p.start){if(n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q),o+=["C"+e(n.start.x),e(n.start.y),e(n.m.x),e(n.m.y),e(n.x),e(n.y)],h)return o;p.start=o,o=["M"+e(n.x),e(n.y)+"C"+e(n.n.x),e(n.n.y),e(n.end.x),e(n.end.y),e(l[5]),e(l[6])].join(),q+=m,j=+l[5],k=+l[6];continue}if(!c&&!d)return n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q)}q+=m,j=+l[5],k=+l[6]}o+=l.shift()+l}return p.end=o,n=c?q:d?p:i(j,k,l[0],l[1],l[2],l[3],l[4],l[5],1)},null,a._.clone)}function i(a,b,c,d,e,f,g,h,i){var j=1-i,k=R(j,3),l=R(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*N.atan2(q-s,r-t)/O;return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}}function j(b,c,e,f,g,h,i,j){a.is(b,"array")||(b=[b,c,e,f,g,h,i,j]);var k=D.apply(null,b);return d(k.min.x,k.min.y,k.max.x-k.min.x,k.max.y-k.min.y)}function k(a,b,c){return b>=a.x&&b<=a.x+a.width&&c>=a.y&&c<=a.y+a.height}function l(a,b){return a=d(a),b=d(b),k(b,a.x,a.y)||k(b,a.x2,a.y)||k(b,a.x,a.y2)||k(b,a.x2,a.y2)||k(a,b.x,b.y)||k(a,b.x2,b.y)||k(a,b.x,b.y2)||k(a,b.x2,b.y2)||(a.x<b.x2&&a.x>b.x||b.x<a.x2&&b.x>a.x)&&(a.y<b.y2&&a.y>b.y||b.y<a.y2&&b.y>a.y)}function m(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function n(a,b,c,d,e,f,g,h,i){null==i&&(i=1),i=i>1?1:0>i?0:i;for(var j=i/2,k=12,l=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;k>p;p++){var q=j*l[p]+j,r=m(q,a,c,e,g),s=m(q,b,d,f,h),t=r*r+s*s;o+=n[p]*N.sqrt(t)}return j*o}function o(a,b,c,d,e,f,g,h,i){if(!(0>i||n(a,b,c,d,e,f,g,h)<i)){var j,k=1,l=k/2,m=k-l,o=.01;for(j=n(a,b,c,d,e,f,g,h,m);S(j-i)>o;)l/=2,m+=(i>j?1:-1)*l,j=n(a,b,c,d,e,f,g,h,m);return m}}function p(a,b,c,d,e,f,g,h){if(!(Q(a,c)<P(e,g)||P(a,c)>Q(e,g)||Q(b,d)<P(f,h)||P(b,d)>Q(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+Q(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+Q(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+Q(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+Q(f,h).toFixed(2)))return{x:l,y:m}}}}function q(a,b,c){var d=j(a),e=j(b);if(!l(d,e))return c?0:[];for(var f=n.apply(0,a),g=n.apply(0,b),h=~~(f/8),k=~~(g/8),m=[],o=[],q={},r=c?0:[],s=0;h+1>s;s++){var t=i.apply(0,a.concat(s/h));m.push({x:t.x,y:t.y,t:s/h})}for(s=0;k+1>s;s++)t=i.apply(0,b.concat(s/k)),o.push({x:t.x,y:t.y,t:s/k});for(s=0;h>s;s++)for(var u=0;k>u;u++){var v=m[s],w=m[s+1],x=o[u],y=o[u+1],z=S(w.x-v.x)<.001?"y":"x",A=S(y.x-x.x)<.001?"y":"x",B=p(v.x,v.y,w.x,w.y,x.x,x.y,y.x,y.y);if(B){if(q[B.x.toFixed(4)]==B.y.toFixed(4))continue;q[B.x.toFixed(4)]=B.y.toFixed(4);var C=v.t+S((B[z]-v[z])/(w[z]-v[z]))*(w.t-v.t),D=x.t+S((B[A]-x[A])/(y[A]-x[A]))*(y.t-x.t);C>=0&&1>=C&&D>=0&&1>=D&&(c?r++:r.push({x:B.x,y:B.y,t1:C,t2:D}))}}return r}function r(a,b){return t(a,b)}function s(a,b){return t(a,b,1)}function t(a,b,c){a=E(a),b=E(b);for(var d,e,f,g,h,i,j,k,l,m,n=c?0:[],o=0,p=a.length;p>o;o++){var r=a[o];if("M"==r[0])d=h=r[1],e=i=r[2];else{"C"==r[0]?(l=[d,e].concat(r.slice(1)),d=l[6],e=l[7]):(l=[d,e,d,e,h,i,h,i],d=h,e=i);for(var s=0,t=b.length;t>s;s++){var u=b[s];if("M"==u[0])f=j=u[1],g=k=u[2];else{"C"==u[0]?(m=[f,g].concat(u.slice(1)),f=m[6],g=m[7]):(m=[f,g,f,g,j,k,j,k],f=j,g=k);var v=q(l,m,c);if(c)n+=v;else{for(var w=0,x=v.length;x>w;w++)v[w].segment1=o,v[w].segment2=s,v[w].bez1=l,v[w].bez2=m;n=n.concat(v)}}}}}return n}function u(a,b,c){var d=v(a);return k(d,b,c)&&t(a,[["M",b,c],["H",d.x2+10]],1)%2==1}function v(a){var b=c(a);if(b.bbox)return J(b.bbox);if(!a)return d();a=E(a);for(var e,f=0,g=0,h=[],i=[],j=0,k=a.length;k>j;j++)if(e=a[j],"M"==e[0])f=e[1],g=e[2],h.push(f),i.push(g);else{var l=D(f,g,e[1],e[2],e[3],e[4],e[5],e[6]);h=h.concat(l.min.x,l.max.x),i=i.concat(l.min.y,l.max.y),f=e[5],g=e[6]}var m=P.apply(0,h),n=P.apply(0,i),o=Q.apply(0,h),p=Q.apply(0,i),q=d(m,n,o-m,p-n);return b.bbox=J(q),q}function w(a,b,c,d,f){if(f)return[["M",+a+ +f,b],["l",c-2*f,0],["a",f,f,0,0,1,f,f],["l",0,d-2*f],["a",f,f,0,0,1,-f,f],["l",2*f-c,0],["a",f,f,0,0,1,-f,-f],["l",0,2*f-d],["a",f,f,0,0,1,f,-f],["z"]];var g=[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]];return g.toString=e,g}function x(a,b,c,d,f){if(null==f&&null==d&&(d=c),a=+a,b=+b,c=+c,d=+d,null!=f)var g=Math.PI/180,h=a+c*Math.cos(-d*g),i=a+c*Math.cos(-f*g),j=b+c*Math.sin(-d*g),k=b+c*Math.sin(-f*g),l=[["M",h,j],["A",c,c,0,+(f-d>180),0,i,k]];else l=[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]];return l.toString=e,l}function y(b){var d=c(b),g=String.prototype.toLowerCase;if(d.rel)return f(d.rel);a.is(b,"array")&&a.is(b&&b[0],"array")||(b=a.parsePathString(b));var h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=b[0][1],j=b[0][2],k=i,l=j,m++,h.push(["M",i,j]));for(var n=m,o=b.length;o>n;n++){var p=h[n]=[],q=b[n];if(q[0]!=g.call(q[0]))switch(p[0]=g.call(q[0]),p[0]){case"a":p[1]=q[1],p[2]=q[2],p[3]=q[3],p[4]=q[4],p[5]=q[5],p[6]=+(q[6]-i).toFixed(3),p[7]=+(q[7]-j).toFixed(3);break;case"v":p[1]=+(q[1]-j).toFixed(3);break;case"m":k=q[1],l=q[2];default:for(var r=1,s=q.length;s>r;r++)p[r]=+(q[r]-(r%2?i:j)).toFixed(3)}else{p=h[n]=[],"m"==q[0]&&(k=q[1]+i,l=q[2]+j);for(var t=0,u=q.length;u>t;t++)h[n][t]=q[t]}var v=h[n].length;switch(h[n][0]){case"z":i=k,j=l;break;case"h":i+=+h[n][v-1];break;case"v":j+=+h[n][v-1];break;default:i+=+h[n][v-2],j+=+h[n][v-1]}}return h.toString=e,d.rel=f(h),h}function z(b){var d=c(b);if(d.abs)return f(d.abs);if(I(b,"array")&&I(b&&b[0],"array")||(b=a.parsePathString(b)),!b||!b.length)return[["M",0,0]];var g,h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=+b[0][1],j=+b[0][2],k=i,l=j,m++,h[0]=["M",i,j]);for(var n,o,p=3==b.length&&"M"==b[0][0]&&"R"==b[1][0].toUpperCase()&&"Z"==b[2][0].toUpperCase(),q=m,r=b.length;r>q;q++){if(h.push(n=[]),o=b[q],g=o[0],g!=g.toUpperCase())switch(n[0]=g.toUpperCase(),n[0]){case"A":n[1]=o[1],n[2]=o[2],n[3]=o[3],n[4]=o[4],n[5]=o[5],n[6]=+o[6]+i,n[7]=+o[7]+j;break;case"V":n[1]=+o[1]+j;break;case"H":n[1]=+o[1]+i;break;case"R":for(var s=[i,j].concat(o.slice(1)),t=2,u=s.length;u>t;t++)s[t]=+s[t]+i,s[++t]=+s[t]+j;h.pop(),h=h.concat(G(s,p));break;case"O":h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);break;case"U":h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));break;case"M":k=+o[1]+i,l=+o[2]+j;default:for(t=1,u=o.length;u>t;t++)n[t]=+o[t]+(t%2?i:j)}else if("R"==g)s=[i,j].concat(o.slice(1)),h.pop(),h=h.concat(G(s,p)),n=["R"].concat(o.slice(-2));else if("O"==g)h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);else if("U"==g)h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));else for(var v=0,w=o.length;w>v;v++)n[v]=o[v];if(g=g.toUpperCase(),"O"!=g)switch(n[0]){case"Z":i=+k,j=+l;break;case"H":i=n[1];break;case"V":j=n[1];break;case"M":k=n[n.length-2],l=n[n.length-1];default:i=n[n.length-2],j=n[n.length-1]}}return h.toString=e,d.abs=f(h),h}function A(a,b,c,d){return[a,b,c,d,c,d]}function B(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]}function C(b,c,d,e,f,g,h,i,j,k){var l,m=120*O/180,n=O/180*(+f||0),o=[],p=a._.cacher(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(b,c,-n),b=l.x,c=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(O/180*f),N.sin(O/180*f),(b-i)/2),r=(c-j)/2,s=q*q/(d*d)+r*r/(e*e);s>1&&(s=N.sqrt(s),d=s*d,e=s*e);var t=d*d,u=e*e,v=(g==h?-1:1)*N.sqrt(S((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*d*r/e+(b+i)/2,x=v*-e*q/d+(c+j)/2,y=N.asin(((c-x)/e).toFixed(9)),z=N.asin(((j-x)/e).toFixed(9));y=w>b?O-y:y,z=w>i?O-z:z,0>y&&(y=2*O+y),0>z&&(z=2*O+z),h&&y>z&&(y-=2*O),!h&&z>y&&(z-=2*O)}var A=z-y;if(S(A)>m){var B=z,D=i,E=j;z=y+m*(h&&z>y?1:-1),i=w+d*N.cos(z),j=x+e*N.sin(z),o=C(i,j,d,e,f,0,h,D,E,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),J=N.tan(A/4),K=4/3*d*J,L=4/3*e*J,M=[b,c],P=[b+K*G,c-L*F],Q=[i+K*I,j-L*H],R=[i,j];if(P[0]=2*M[0]-P[0],P[1]=2*M[1]-P[1],k)return[P,Q,R].concat(o);o=[P,Q,R].concat(o).join().split(",");for(var T=[],U=0,V=o.length;V>U;U++)T[U]=U%2?p(o[U-1],o[U],n).y:p(o[U],o[U+1],n).x;return T}function D(a,b,c,d,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=[],r=[[],[]],s=0;2>s;++s)if(0==s?(j=6*a-12*c+6*e,i=-3*a+9*c-9*e+3*g,k=3*c-3*a):(j=6*b-12*d+6*f,i=-3*b+9*d-9*f+3*h,k=3*d-3*b),S(i)<1e-12){if(S(j)<1e-12)continue;l=-k/j,l>0&&1>l&&q.push(l)}else o=j*j-4*k*i,p=N.sqrt(o),0>o||(m=(-j+p)/(2*i),m>0&&1>m&&q.push(m),n=(-j-p)/(2*i),n>0&&1>n&&q.push(n));for(var t,u=q.length,v=u;u--;)l=q[u],t=1-l,r[0][u]=t*t*t*a+3*t*t*l*c+3*t*l*l*e+l*l*l*g,r[1][u]=t*t*t*b+3*t*t*l*d+3*t*l*l*f+l*l*l*h;return r[0][v]=a,r[1][v]=b,r[0][v+1]=g,r[1][v+1]=h,r[0].length=r[1].length=v+2,{min:{x:P.apply(0,r[0]),y:P.apply(0,r[1])},max:{x:Q.apply(0,r[0]),y:Q.apply(0,r[1])}}}function E(a,b){var d=!b&&c(a);if(!b&&d.curve)return f(d.curve);for(var e=z(a),g=b&&z(b),h={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},i={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},j=(function(a,b,c){var d,e;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"].concat(C.apply(0,[b.x,b.y].concat(a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e].concat(a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"].concat(B(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"].concat(B(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"].concat(A(b.x,b.y,a[1],a[2]));break;case"H":a=["C"].concat(A(b.x,b.y,a[1],b.y));break;case"V":a=["C"].concat(A(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"].concat(A(b.x,b.y,b.X,b.Y))}return a}),k=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)m[b]="A",g&&(n[b]="A"),a.splice(b++,0,["C"].concat(c.splice(0,6)));a.splice(b,1),r=Q(e.length,g&&g.length||0)}},l=function(a,b,c,d,f){a&&b&&"M"==a[f][0]&&"M"!=b[f][0]&&(b.splice(f,0,["M",d.x,d.y]),c.bx=0,c.by=0,c.x=a[f][1],c.y=a[f][2],r=Q(e.length,g&&g.length||0))},m=[],n=[],o="",p="",q=0,r=Q(e.length,g&&g.length||0);r>q;q++){e[q]&&(o=e[q][0]),"C"!=o&&(m[q]=o,q&&(p=m[q-1])),e[q]=j(e[q],h,p),"A"!=m[q]&&"C"==o&&(m[q]="C"),k(e,q),g&&(g[q]&&(o=g[q][0]),"C"!=o&&(n[q]=o,q&&(p=n[q-1])),g[q]=j(g[q],i,p),"A"!=n[q]&&"C"==o&&(n[q]="C"),k(g,q)),l(e,g,h,i,q),l(g,e,i,h,q);var s=e[q],t=g&&g[q],u=s.length,v=g&&t.length;h.x=s[u-2],h.y=s[u-1],h.bx=M(s[u-4])||h.x,h.by=M(s[u-3])||h.y,i.bx=g&&(M(t[v-4])||i.x),i.by=g&&(M(t[v-3])||i.y),i.x=g&&t[v-2],i.y=g&&t[v-1]}return g||(d.curve=f(e)),g?[e,g]:e}function F(a,b){if(!b)return a;var c,d,e,f,g,h,i;for(a=E(a),e=0,g=a.length;g>e;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a}function G(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}var H=b.prototype,I=a.is,J=a._.clone,K="hasOwnProperty",L=/,?([a-z]),?/gi,M=parseFloat,N=Math,O=N.PI,P=N.min,Q=N.max,R=N.pow,S=N.abs,T=h(1),U=h(),V=h(0,1),W=a._unit2px,X={path:function(a){return a.attr("path")},circle:function(a){var b=W(a);return x(b.cx,b.cy,b.r)},ellipse:function(a){var b=W(a);return x(b.cx||0,b.cy||0,b.rx,b.ry)},rect:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height,b.rx,b.ry)},image:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height)},line:function(a){return"M"+[a.attr("x1")||0,a.attr("y1")||0,a.attr("x2"),a.attr("y2")]},polyline:function(a){return"M"+a.attr("points")},polygon:function(a){return"M"+a.attr("points")+"z"},deflt:function(a){var b=a.node.getBBox();return w(b.x,b.y,b.width,b.height)}};a.path=c,a.path.getTotalLength=T,a.path.getPointAtLength=U,a.path.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return V(a,b).end;var d=V(a,c,1);return b?V(d,b).end:d},H.getTotalLength=function(){return this.node.getTotalLength?this.node.getTotalLength():void 0},H.getPointAtLength=function(a){return U(this.attr("d"),a)},H.getSubpath=function(b,c){return a.path.getSubpath(this.attr("d"),b,c)},a._.box=d,a.path.findDotsAtSegment=i,a.path.bezierBBox=j,a.path.isPointInsideBBox=k,a.closest=function(b,c,e,f){for(var g=100,h=d(b-g/2,c-g/2,g,g),i=[],j=e[0].hasOwnProperty("x")?function(a){return{x:e[a].x,y:e[a].y}}:function(a){return{x:e[a],y:f[a]}},l=0;1e6>=g&&!l;){for(var m=0,n=e.length;n>m;m++){var o=j(m);if(k(h,o.x,o.y)){l++,i.push(o);break}}l||(g*=2,h=d(b-g/2,c-g/2,g,g))}if(1e6!=g){var p,q=1/0;for(m=0,n=i.length;n>m;m++){var r=a.len(b,c,i[m].x,i[m].y);q>r&&(q=r,i[m].len=r,p=i[m])}return p}},a.path.isBBoxIntersect=l,a.path.intersection=r,a.path.intersectionNumber=s,a.path.isPointInside=u,a.path.getBBox=v,a.path.get=X,a.path.toRelative=y,a.path.toAbsolute=z,a.path.toCubic=E,a.path.map=F,a.path.toString=e,a.path.clone=f}),d.plugin(function(a){var d=Math.max,e=Math.min,f=function(a){if(this.items=[],this.bindings={},this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)a[b]&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},g=f.prototype;g.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],a&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},g.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},g.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this},g.animate=function(d,e,f,g){"function"!=typeof f||f.length||(g=f,f=c.linear),d instanceof a._.Animation&&(g=d.callback,f=d.easing,e=f.dur,d=d.attr);var h=arguments;if(a.is(d,"array")&&a.is(h[h.length-1],"array"))var i=!0;var j,k=function(){j?this.b=j:j=this.b},l=0,m=this,n=g&&function(){++l==m.length&&g.call(this) +};return this.forEach(function(a,c){b.once("snap.animcreated."+a.id,k),i?h[c]&&a.animate.apply(a,h[c]):a.animate(d,e,f,n)})},g.remove=function(){for(;this.length;)this.pop().remove();return this},g.bind=function(a,b,c){var d={};if("function"==typeof b)this.bindings[a]=b;else{var e=c||a;this.bindings[a]=function(a){d[e]=a,b.attr(d)}}return this},g.attr=function(a){var b={};for(var c in a)this.bindings[c]?this.bindings[c](a[c]):b[c]=a[c];for(var d=0,e=this.items.length;e>d;d++)this.items[d].attr(b);return this},g.clear=function(){for(;this.length;)this.pop()},g.splice=function(a,b){a=0>a?d(this.length+a,0):a,b=d(0,e(this.length-a,b));var c,g=[],h=[],i=[];for(c=2;c<arguments.length;c++)i.push(arguments[c]);for(c=0;b>c;c++)h.push(this[a+c]);for(;c<this.length-a;c++)g.push(this[a+c]);var j=i.length;for(c=0;c<j+g.length;c++)this.items[a+c]=this[a+c]=j>c?i[c]:g[c-j];for(c=this.items.length=this.length-=b-j;this[c];)delete this[c++];return new f(h)},g.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0;return!1},g.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},g.getBBox=function(){for(var a=[],b=[],c=[],f=[],g=this.items.length;g--;)if(!this.items[g].removed){var h=this.items[g].getBBox();a.push(h.x),b.push(h.y),c.push(h.x+h.width),f.push(h.y+h.height)}return a=e.apply(0,a),b=e.apply(0,b),c=d.apply(0,c),f=d.apply(0,f),{x:a,y:b,x2:c,y2:f,width:c-a,height:f-b,cx:a+(c-a)/2,cy:b+(f-b)/2}},g.clone=function(a){a=new f;for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},g.toString=function(){return"Snap‘s set"},g.type="set",a.Set=f,a.set=function(){var a=new f;return arguments.length&&a.push.apply(a,Array.prototype.slice.call(arguments,0)),a}}),d.plugin(function(a,c){function d(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}}function e(b,c,e){c=p(c).replace(/\.{3}|\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];for(var f,g,h,i,l=Math.max(b.length,c.length),m=[],n=[],o=0;l>o;o++){if(h=b[o]||d(c[o]),i=c[o]||d(h),h[0]!=i[0]||"r"==h[0].toLowerCase()&&(h[2]!=i[2]||h[3]!=i[3])||"s"==h[0].toLowerCase()&&(h[3]!=i[3]||h[4]!=i[4])){b=a._.transform2matrix(b,e()),c=a._.transform2matrix(c,e()),m=[["m",b.a,b.b,b.c,b.d,b.e,b.f]],n=[["m",c.a,c.b,c.c,c.d,c.e,c.f]];break}for(m[o]=[],n[o]=[],f=0,g=Math.max(h.length,i.length);g>f;f++)f in h&&(m[o][f]=h[f]),f in i&&(n[o][f]=i[f])}return{from:k(m),to:k(n),f:j(m)}}function f(a){return a}function g(a){return function(b){return+b.toFixed(3)+a}}function h(a){return a.join(" ")}function i(b){return a.rgb(b[0],b[1],b[2])}function j(a){var b,c,d,e,f,g,h=0,i=[];for(b=0,c=a.length;c>b;b++){for(f="[",g=['"'+a[b][0]+'"'],d=1,e=a[b].length;e>d;d++)g[d]="val["+h++ +"]";f+=g+"]",i[b]=f}return Function("val","return Snap.path.toString.call(["+i+"])")}function k(a){for(var b=[],c=0,d=a.length;d>c;c++)for(var e=1,f=a[c].length;f>e;e++)b.push(a[c][e]);return b}function l(a){return isFinite(parseFloat(a))}function m(b,c){return a.is(b,"array")&&a.is(c,"array")?b.toString()==c.toString():!1}var n={},o=/[a-z]+$/i,p=String;n.stroke=n.fill="colour",c.prototype.equal=function(a,c){return b("snap.util.equal",this,a,c).firstDefined()},b.on("snap.util.equal",function(b,c){var d,q,r=p(this.attr(b)||""),s=this;if(l(r)&&l(c))return{from:parseFloat(r),to:parseFloat(c),f:f};if("colour"==n[b])return d=a.color(r),q=a.color(c),{from:[d.r,d.g,d.b,d.opacity],to:[q.r,q.g,q.b,q.opacity],f:i};if("viewBox"==b)return d=this.attr(b).vb.split(" ").map(Number),q=c.split(" ").map(Number),{from:d,to:q,f:h};if("transform"==b||"gradientTransform"==b||"patternTransform"==b)return c instanceof a.Matrix&&(c=c.toTransformString()),a._.rgTransform.test(c)||(c=a._.svgTransform2string(c)),e(r,c,function(){return s.getBBox(1)});if("d"==b||"path"==b)return d=a.path.toCubic(r,c),{from:k(d[0]),to:k(d[1]),f:j(d[0])};if("points"==b)return d=p(r).split(a._.separator),q=p(c).split(a._.separator),{from:d,to:q,f:function(a){return a}};var t=r.match(o),u=p(c).match(o);return t&&m(t,u)?{from:parseFloat(r),to:parseFloat(c),f:g(t)}:{from:this.asPX(b),to:this.asPX(b,c),f:f}})}),d.plugin(function(a,c,d,e){for(var f=c.prototype,g="hasOwnProperty",h=("createTouch"in e.doc),i=["click","dblclick","mousedown","mousemove","mouseout","mouseover","mouseup","touchstart","touchmove","touchend","touchcancel"],j={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},k=(function(a,b){var c="y"==a?"scrollTop":"scrollLeft",d=b&&b.node?b.node.ownerDocument:e.doc;return d[c in d.documentElement?"documentElement":"body"][c]}),l=function(){return this.originalEvent.preventDefault()},m=function(){return this.originalEvent.stopPropagation()},n=function(a,b,c,d){var e=h&&j[b]?j[b]:b,f=function(e){var f=k("y",d),i=k("x",d);if(h&&j[g](b))for(var n=0,o=e.targetTouches&&e.targetTouches.length;o>n;n++)if(e.targetTouches[n].target==a||a.contains(e.targetTouches[n].target)){var p=e;e=e.targetTouches[n],e.originalEvent=p,e.preventDefault=l,e.stopPropagation=m;break}var q=e.clientX+i,r=e.clientY+f;return c.call(d,e,q,r)};return b!==e&&a.addEventListener(b,f,!1),a.addEventListener(e,f,!1),function(){return b!==e&&a.removeEventListener(b,f,!1),a.removeEventListener(e,f,!1),!0}},o=[],p=function(a){for(var c,d=a.clientX,e=a.clientY,f=k("y"),g=k("x"),i=o.length;i--;){if(c=o[i],h){for(var j,l=a.touches&&a.touches.length;l--;)if(j=a.touches[l],j.identifier==c.el._drag.id||c.el.node.contains(j.target)){d=j.clientX,e=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();{var m=c.el.node;m.nextSibling,m.parentNode,m.style.display}d+=g,e+=f,b("snap.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},q=function(c){a.unmousemove(p).unmouseup(q);for(var d,e=o.length;e--;)d=o[e],d.el._drag={},b("snap.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,c),b.off("snap.drag.*."+d.el.id);o=[]},r=i.length;r--;)!function(b){a[b]=f[b]=function(c,d){if(a.is(c,"function"))this.events=this.events||[],this.events.push({name:b,f:c,unbind:n(this.node||document,b,c,d||this)});else for(var e=0,f=this.events.length;f>e;e++)if(this.events[e].name==b)try{this.events[e].f.call(this)}catch(g){}return this},a["un"+b]=f["un"+b]=function(a){for(var c=this.events||[],d=c.length;d--;)if(c[d].name==b&&(c[d].f==a||!a))return c[d].unbind(),c.splice(d,1),!c.length&&delete this.events,this;return this}}(i[r]);f.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},f.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var s=[];f.drag=function(c,d,e,f,g,h){function i(i,j,l){(i.originalEvent||i).preventDefault(),k._drag.x=j,k._drag.y=l,k._drag.id=i.identifier,!o.length&&a.mousemove(p).mouseup(q),o.push({el:k,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("snap.drag.start."+k.id,d),c&&b.on("snap.drag.move."+k.id,c),e&&b.on("snap.drag.end."+k.id,e),b("snap.drag.start."+k.id,g||f||k,j,l,i)}function j(a,c,d){b("snap.draginit."+k.id,k,a,c,d)}var k=this;if(!arguments.length){var l;return k.drag(function(a,b){this.attr({transform:l+(l?"T":"t")+[a,b]})},function(){l=this.transform().local})}return b.on("snap.draginit."+k.id,i),k._drag={},s.push({el:k,start:i,init:j}),k.mousedown(j),k},f.undrag=function(){for(var c=s.length;c--;)s[c].el==this&&(this.unmousedown(s[c].init),s.splice(c,1),b.unbind("snap.drag.*."+this.id),b.unbind("snap.draginit."+this.id));return!s.length&&a.unmousemove(p).unmouseup(q),this}}),d.plugin(function(a,c,d){var e=(c.prototype,d.prototype),f=/^\s*url\((.+)\)/,g=String,h=a._.$;a.filter={},e.filter=function(b){var d=this;"svg"!=d.type&&(d=d.paper);var e=a.parse(g(b)),f=a._.id(),i=(d.node.offsetWidth,d.node.offsetHeight,h("filter"));return h(i,{id:f,filterUnits:"userSpaceOnUse"}),i.appendChild(e.node),d.defs.appendChild(i),new c(i)},b.on("snap.util.getattr.filter",function(){b.stop();var c=h(this.node,"filter");if(c){var d=g(c).match(f);return d&&a.select(d[1])}}),b.on("snap.util.attr.filter",function(d){if(d instanceof c&&"filter"==d.type){b.stop();var e=d.node.id;e||(h(d.node,{id:d.id}),e=d.id),h(this.node,{filter:a.url(e)})}d&&"none"!=d||(b.stop(),this.node.removeAttribute("filter"))}),a.filter.blur=function(b,c){null==b&&(b=2);var d=null==c?b:[b,c];return a.format('<feGaussianBlur stdDeviation="{def}"/>',{def:d})},a.filter.blur.toString=function(){return this()},a.filter.shadow=function(b,c,d,e,f){return"string"==typeof d&&(e=d,f=e,d=4),"string"!=typeof e&&(f=e,e="#000"),e=e||"#000",null==d&&(d=4),null==f&&(f=1),null==b&&(b=0,c=2),null==c&&(c=b),e=a.color(e),a.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>',{color:e,dx:b,dy:c,blur:d,opacity:f})},a.filter.shadow.toString=function(){return this()},a.filter.grayscale=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>',{a:.2126+.7874*(1-b),b:.7152-.7152*(1-b),c:.0722-.0722*(1-b),d:.2126-.2126*(1-b),e:.7152+.2848*(1-b),f:.0722-.0722*(1-b),g:.2126-.2126*(1-b),h:.0722+.9278*(1-b)})},a.filter.grayscale.toString=function(){return this()},a.filter.sepia=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>',{a:.393+.607*(1-b),b:.769-.769*(1-b),c:.189-.189*(1-b),d:.349-.349*(1-b),e:.686+.314*(1-b),f:.168-.168*(1-b),g:.272-.272*(1-b),h:.534-.534*(1-b),i:.131+.869*(1-b)})},a.filter.sepia.toString=function(){return this()},a.filter.saturate=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="saturate" values="{amount}"/>',{amount:1-b})},a.filter.saturate.toString=function(){return this()},a.filter.hueRotate=function(b){return b=b||0,a.format('<feColorMatrix type="hueRotate" values="{angle}"/>',{angle:b})},a.filter.hueRotate.toString=function(){return this()},a.filter.invert=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>',{amount:b,amount2:1-b})},a.filter.invert.toString=function(){return this()},a.filter.brightness=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>',{amount:b})},a.filter.brightness.toString=function(){return this()},a.filter.contrast=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>',{amount:b,amount2:.5-b/2})},a.filter.contrast.toString=function(){return this()}}),d.plugin(function(a,b){var c=a._.box,d=a.is,e=/^[^a-z]*([tbmlrc])/i,f=function(){return"T"+this.dx+","+this.dy};b.prototype.getAlign=function(a,b){null==b&&d(a,"string")&&(b=a,a=null),a=a||this.paper;var g=a.getBBox?a.getBBox():c(a),h=this.getBBox(),i={};switch(b=b&&b.match(e),b=b?b[1].toLowerCase():"c"){case"t":i.dx=0,i.dy=g.y-h.y;break;case"b":i.dx=0,i.dy=g.y2-h.y2;break;case"m":i.dx=0,i.dy=g.cy-h.cy;break;case"l":i.dx=g.x-h.x,i.dy=0;break;case"r":i.dx=g.x2-h.x2,i.dy=0;break;default:i.dx=g.cx-h.cx,i.dy=0}return i.toString=f,i},b.prototype.align=function(a,b){return this.transform("..."+this.getAlign(a,b))}}),d}); diff --git a/web/pgadmin/misc/static/explain/js/snap.svg.js b/web/pgadmin/misc/static/explain/js/snap.svg.js new file mode 100644 index 0000000..ef0fb6d --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg.js @@ -0,0 +1,8149 @@ +// Snap.svg 0.4.1 +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// build: 2015-04-13 +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ┌────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.4.2 - JavaScript Events Library │ \\ +// ├────────────────────────────────────────────────────────────┤ \\ +// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// └────────────────────────────────────────────────────────────┘ \\ +(function (glob) { + var version = "0.4.2", + has = "hasOwnProperty", + separator = /[\.\/]/, + comaseparator = /\s*,\s*/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + firstDefined = function () { + for (var i = 0, ii = this.length; i < ii; i++) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + lastDefined = function () { + var i = this.length; + while (--i) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + /*\ + * eve + [ method ] + * Fires event with given `name`, given scope and other parameters. + > Arguments + - name (string) name of the *event*, dot (`.`) or slash (`/`) separated + - scope (object) context for the event handlers + - varargs (...) the rest of arguments will be sent to event handlers + = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value. + \*/ + eve = function (name, scope) { + name = String(name); + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + ce = current_event, + errors = []; + out.firstDefined = firstDefined; + out.lastDefined = lastDefined; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + break; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + } + } + stop = oldstop; + current_event = ce; + return out; + }; + // Undocumented. Debug only. + eve._events = events; + /*\ + * eve.listeners + [ method ] + * Internal method which gives you array of all event handlers that will be triggered by the given `name`. + > Arguments + - name (string) name of the event, dot (`.`) or slash (`/`) separated + = (array) array of event handlers + \*/ + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + /*\ + * eve.on + [ method ] + ** + * Binds given event handler with a given name. You can use wildcards “`*`” for the names: + | eve.on("*.under.*", f); + | eve("mouse.under.floor"); // triggers f + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. + > Example: + | eve.on("mouse", eatIt)(2); + | eve.on("mouse", scream); + | eve.on("mouse", catchIt)(1); + * This will ensure that `catchIt` function will be called before `eatIt`. + * + * If you want to put your handler before non-indexed handlers, specify a negative value. + * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. + \*/ + eve.on = function (name, f) { + name = String(name); + if (typeof f != "function") { + return function () {}; + } + var names = name.split(comaseparator); + for (var i = 0, ii = names.length; i < ii; i++) { + (function (name) { + var names = name.split(separator), + e = events, + exist; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + exist = true; + break; + } + !exist && e.f.push(f); + }(names[i])); + } + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + /*\ + * eve.f + [ method ] + ** + * Returns function that will fire given event with optional arguments. + * Arguments that will be passed to the result function will be also + * concated to the list of final arguments. + | el.onclick = eve.f("click", 1, 2); + | eve.on("click", function (a, b, c) { + | console.log(a, b, c); // 1, 2, [event object] + | }); + > Arguments + - event (string) event name + - varargs (…) and any other arguments + = (function) possible event handler function + \*/ + eve.f = function (event) { + var attrs = [].slice.call(arguments, 1); + return function () { + eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); + }; + }; + /*\ + * eve.stop + [ method ] + ** + * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. + \*/ + eve.stop = function () { + stop = 1; + }; + /*\ + * eve.nt + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + > Arguments + ** + - subname (string) #optional subname of the event + ** + = (string) name of the event, if `subname` is not specified + * or + = (boolean) `true`, if current event’s name contains `subname` + \*/ + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + /*\ + * eve.nts + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + ** + = (array) names of the event + \*/ + eve.nts = function () { + return current_event.split(separator); + }; + /*\ + * eve.off + [ method ] + ** + * Removes given function from the list of event listeners assigned to given name. + * If no arguments specified all the events will be cleared. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + \*/ + /*\ + * eve.unbind + [ method ] + ** + * See @eve.off + \*/ + eve.off = eve.unbind = function (name, f) { + if (!name) { + eve._events = events = {n: {}}; + return; + } + var names = name.split(comaseparator); + if (names.length > 1) { + for (var i = 0, ii = names.length; i < ii; i++) { + eve.off(names[i], f); + } + return; + } + names = name.split(separator); + var e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + /*\ + * eve.once + [ method ] + ** + * Binds given event handler with a given name to only run once then unbind itself. + | eve.once("login", f); + | eve("login"); // triggers f + | eve("login"); // no listeners + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) same return function as @eve.on + \*/ + eve.once = function (name, f) { + var f2 = function () { + eve.unbind(name, f2); + return f.apply(this, arguments); + }; + return eve.on(name, f2); + }; + /*\ + * eve.version + [ property (string) ] + ** + * Current version of the library. + \*/ + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define === "function" && define.amd ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); +})(this); + +(function (glob, factory) { + // AMD support + if (typeof define == "function" && define.amd) { + // Define as an anonymous module + define(["eve"], function (eve) { + return factory(glob, eve); + }); + } else if (typeof exports != 'undefined') { + // Next for Node.js or CommonJS + var eve = require('eve'); + module.exports = factory(glob, eve); + } else { + // Browser globals (glob is window) + // Snap adds itself to window + factory(glob, glob.eve); + } +}(window || this, function (window, eve) { +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +var mina = (function (eve) { + var animations = {}, + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + isArray = Array.isArray || function (a) { + return a instanceof Array || + Object.prototype.toString.call(a) == "[object Array]"; + }, + idgen = 0, + idprefix = "M" + (+new Date).toString(36), + ID = function () { + return idprefix + (idgen++).toString(36); + }, + diff = function (a, b, A, B) { + if (isArray(a)) { + res = []; + for (var i = 0, ii = a.length; i < ii; i++) { + res[i] = diff(a[i], b, A[i], B); + } + return res; + } + var dif = (A - a) / (B - b); + return function (bb) { + return a + dif * (bb - b); + }; + }, + timer = Date.now || function () { + return +new Date; + }, + sta = function (val) { + var a = this; + if (val == null) { + return a.s; + } + var ds = a.s - val; + a.b += a.dur * ds; + a.B += a.dur * ds; + a.s = val; + }, + speed = function (val) { + var a = this; + if (val == null) { + return a.spd; + } + a.spd = val; + }, + duration = function (val) { + var a = this; + if (val == null) { + return a.dur; + } + a.s = a.s * val / a.dur; + a.dur = val; + }, + stopit = function () { + var a = this; + delete animations[a.id]; + a.update(); + eve("mina.stop." + a.id, a); + }, + pause = function () { + var a = this; + if (a.pdif) { + return; + } + delete animations[a.id]; + a.update(); + a.pdif = a.get() - a.b; + }, + resume = function () { + var a = this; + if (!a.pdif) { + return; + } + a.b = a.get() - a.pdif; + delete a.pdif; + animations[a.id] = a; + }, + update = function () { + var a = this, + res; + if (isArray(a.start)) { + res = []; + for (var j = 0, jj = a.start.length; j < jj; j++) { + res[j] = +a.start[j] + + (a.end[j] - a.start[j]) * a.easing(a.s); + } + } else { + res = +a.start + (a.end - a.start) * a.easing(a.s); + } + a.set(res); + }, + frame = function () { + var len = 0; + for (var i in animations) if (animations.hasOwnProperty(i)) { + var a = animations[i], + b = a.get(), + res; + len++; + a.s = (b - a.b) / (a.dur / a.spd); + if (a.s >= 1) { + delete animations[i]; + a.s = 1; + len--; + (function (a) { + setTimeout(function () { + eve("mina.finish." + a.id, a); + }); + }(a)); + } + a.update(); + } + len && requestAnimFrame(frame); + }, + /*\ + * mina + [ method ] + ** + * Generic animation of numbers + ** + - a (number) start _slave_ number + - A (number) end _slave_ number + - b (number) start _master_ number (start time in general case) + - B (number) end _master_ number (end time in gereal case) + - get (function) getter of _master_ number (see @mina.time) + - set (function) setter of _slave_ number + - easing (function) #optional easing function, default is @mina.linear + = (object) animation descriptor + o { + o id (string) animation id, + o start (number) start _slave_ number, + o end (number) end _slave_ number, + o b (number) start _master_ number, + o s (number) animation status (0..1), + o dur (number) animation duration, + o spd (number) animation speed, + o get (function) getter of _master_ number (see @mina.time), + o set (function) setter of _slave_ number, + o easing (function) easing function, default is @mina.linear, + o status (function) status getter/setter, + o speed (function) speed getter/setter, + o duration (function) duration getter/setter, + o stop (function) animation stopper + o pause (function) pauses the animation + o resume (function) resumes the animation + o update (function) calles setter with the right value of the animation + o } + \*/ + mina = function (a, A, b, B, get, set, easing) { + var anim = { + id: ID(), + start: a, + end: A, + b: b, + s: 0, + dur: B - b, + spd: 1, + get: get, + set: set, + easing: easing || mina.linear, + status: sta, + speed: speed, + duration: duration, + stop: stopit, + pause: pause, + resume: resume, + update: update + }; + animations[anim.id] = anim; + var len = 0, i; + for (i in animations) if (animations.hasOwnProperty(i)) { + len++; + if (len == 2) { + break; + } + } + len == 1 && requestAnimFrame(frame); + return anim; + }; + /*\ + * mina.time + [ method ] + ** + * Returns the current time. Equivalent to: + | function () { + | return (new Date).getTime(); + | } + \*/ + mina.time = timer; + /*\ + * mina.getById + [ method ] + ** + * Returns an animation by its id + - id (string) animation's id + = (object) See @mina + \*/ + mina.getById = function (id) { + return animations[id] || null; + }; + + /*\ + * mina.linear + [ method ] + ** + * Default linear easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.linear = function (n) { + return n; + }; + /*\ + * mina.easeout + [ method ] + ** + * Easeout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeout = function (n) { + return Math.pow(n, 1.7); + }; + /*\ + * mina.easein + [ method ] + ** + * Easein easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easein = function (n) { + return Math.pow(n, .48); + }; + /*\ + * mina.easeinout + [ method ] + ** + * Easeinout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeinout = function (n) { + if (n == 1) { + return 1; + } + if (n == 0) { + return 0; + } + var q = .48 - n / 1.04, + Q = Math.sqrt(.1734 + q * q), + x = Q - q, + X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }; + /*\ + * mina.backin + [ method ] + ** + * Backin easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backin = function (n) { + if (n == 1) { + return 1; + } + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }; + /*\ + * mina.backout + [ method ] + ** + * Backout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backout = function (n) { + if (n == 0) { + return 0; + } + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }; + /*\ + * mina.elastic + [ method ] + ** + * Elastic easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.elastic = function (n) { + if (n == !!n) { + return n; + } + return Math.pow(2, -10 * n) * Math.sin((n - .075) * + (2 * Math.PI) / .3) + 1; + }; + /*\ + * mina.bounce + [ method ] + ** + * Bounce easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.bounce = function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + }; + window.mina = mina; + return mina; +})(typeof eve == "undefined" ? function () {} : eve); +// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var Snap = (function(root) { +Snap.version = "0.4.0"; +/*\ + * Snap + [ method ] + ** + * Creates a drawing surface or wraps existing SVG element. + ** + - width (number|string) width of surface + - height (number|string) height of surface + * or + - DOM (SVGElement) element to be wrapped into Snap structure + * or + - array (array) array of elements (will return set of elements) + * or + - query (string) CSS query selector + = (object) @Element +\*/ +function Snap(w, h) { + if (w) { + if (w.nodeType) { + return wrap(w); + } + if (is(w, "array") && Snap.set) { + return Snap.set.apply(Snap, w); + } + if (w instanceof Element) { + return w; + } + if (h == null) { + w = glob.doc.querySelector(String(w)); + return wrap(w); + } + } + w = w == null ? "100%" : w; + h = h == null ? "100%" : h; + return new Paper(w, h); +} +Snap.toString = function () { + return "Snap v" + this.version; +}; +Snap._ = {}; +var glob = { + win: root.window, + doc: root.window.document +}; +Snap._.glob = glob; +var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + round = math.round, + E = "", + S = " ", + objectToString = Object.prototype.toString, + ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + reURLValue = /^url\(#?([^)]+)\)$/, + separator = Snap._.separator = /[,\s]+/, + whitespace = /[\s]/g, + commaSpaces = /[\s]*,[\s]*/, + hsrg = {hs: 1, rg: 1}, + pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig, + idgen = 0, + idprefix = "S" + (+new Date).toString(36), + ID = function (el) { + return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36); + }, + xlink = "http://www.w3.org/1999/xlink", + xmlns = "http://www.w3.org/2000/svg", + hub = {}, + URL = Snap.url = function (url) { + return "url('#" + url + "')"; + }; + +function $(el, attr) { + if (attr) { + if (el == "#text") { + el = glob.doc.createTextNode(attr.text || attr["#text"] || ""); + } + if (el == "#comment") { + el = glob.doc.createComment(attr.text || attr["#text"] || ""); + } + if (typeof el == "string") { + el = $(el); + } + if (typeof attr == "string") { + if (el.nodeType == 1) { + if (attr.substring(0, 6) == "xlink:") { + return el.getAttributeNS(xlink, attr.substring(6)); + } + if (attr.substring(0, 4) == "xml:") { + return el.getAttributeNS(xmlns, attr.substring(4)); + } + return el.getAttribute(attr); + } else if (attr == "text") { + return el.nodeValue; + } else { + return null; + } + } + if (el.nodeType == 1) { + for (var key in attr) if (attr[has](key)) { + var val = Str(attr[key]); + if (val) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), val); + } else if (key.substring(0, 4) == "xml:") { + el.setAttributeNS(xmlns, key.substring(4), val); + } else { + el.setAttribute(key, val); + } + } else { + el.removeAttribute(key); + } + } + } else if ("text" in attr) { + el.nodeValue = attr.text; + } + } else { + el = glob.doc.createElementNS(xmlns, el); + } + return el; +} +Snap._.$ = $; +Snap._.id = ID; +function getAttrs(el) { + var attrs = el.attributes, + name, + out = {}; + for (var i = 0; i < attrs.length; i++) { + if (attrs[i].namespaceURI == xlink) { + name = "xlink:"; + } else { + name = ""; + } + name += attrs[i].name; + out[name] = attrs[i].textContent; + } + return out; +} +function is(o, type) { + type = Str.prototype.toLowerCase.call(type); + if (type == "finite") { + return isFinite(o); + } + if (type == "array" && + (o instanceof Array || Array.isArray && Array.isArray(o))) { + return true; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; +} +/*\ + * Snap.format + [ method ] + ** + * Replaces construction of type `{<name>}` to the corresponding argument + ** + - token (string) string to format + - json (object) object which properties are used as a replacement + = (string) formatted string + > Usage + | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z" + | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { + | x: 10, + | y: 20, + | dim: { + | width: 40, + | height: 50, + | "negative width": -40 + | } + | })); +\*/ +Snap.format = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return Str(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; +})(); +function clone(obj) { + if (typeof obj == "function" || Object(obj) !== obj) { + return obj; + } + var res = new obj.constructor; + for (var key in obj) if (obj[has](key)) { + res[key] = clone(obj[key]); + } + return res; +} +Snap._.clone = clone; +function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } +} +function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f.apply(scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; +} +Snap._.cacher = cacher; +function angle(x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3); + } +} +function rad(deg) { + return deg % 360 * PI / 180; +} +function deg(rad) { + return rad * 180 / PI % 360; +} +function x_y() { + return this.x + S + this.y; +} +function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; +} + +/*\ + * Snap.rad + [ method ] + ** + * Transform angle to radians + - deg (number) angle in degrees + = (number) angle in radians +\*/ +Snap.rad = rad; +/*\ + * Snap.deg + [ method ] + ** + * Transform angle to degrees + - rad (number) angle in radians + = (number) angle in degrees +\*/ +Snap.deg = deg; +/*\ + * Snap.sin + [ method ] + ** + * Equivalent to `Math.sin()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) sin +\*/ +Snap.sin = function (angle) { + return math.sin(Snap.rad(angle)); +}; +/*\ + * Snap.tan + [ method ] + ** + * Equivalent to `Math.tan()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) tan +\*/ +Snap.tan = function (angle) { + return math.tan(Snap.rad(angle)); +}; +/*\ + * Snap.cos + [ method ] + ** + * Equivalent to `Math.cos()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) cos +\*/ +Snap.cos = function (angle) { + return math.cos(Snap.rad(angle)); +}; +/*\ + * Snap.asin + [ method ] + ** + * Equivalent to `Math.asin()` only works with degrees, not radians. + - num (number) value + = (number) asin in degrees +\*/ +Snap.asin = function (num) { + return Snap.deg(math.asin(num)); +}; +/*\ + * Snap.acos + [ method ] + ** + * Equivalent to `Math.acos()` only works with degrees, not radians. + - num (number) value + = (number) acos in degrees +\*/ +Snap.acos = function (num) { + return Snap.deg(math.acos(num)); +}; +/*\ + * Snap.atan + [ method ] + ** + * Equivalent to `Math.atan()` only works with degrees, not radians. + - num (number) value + = (number) atan in degrees +\*/ +Snap.atan = function (num) { + return Snap.deg(math.atan(num)); +}; +/*\ + * Snap.atan2 + [ method ] + ** + * Equivalent to `Math.atan2()` only works with degrees, not radians. + - num (number) value + = (number) atan2 in degrees +\*/ +Snap.atan2 = function (num) { + return Snap.deg(math.atan2(num)); +}; +/*\ + * Snap.angle + [ method ] + ** + * Returns an angle between two or three points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + - x3 (number) #optional x coord of third point + - y3 (number) #optional y coord of third point + = (number) angle in degrees +\*/ +Snap.angle = angle; +/*\ + * Snap.len + [ method ] + ** + * Returns distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len = function (x1, y1, x2, y2) { + return Math.sqrt(Snap.len2(x1, y1, x2, y2)); +}; +/*\ + * Snap.len2 + [ method ] + ** + * Returns squared distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len2 = function (x1, y1, x2, y2) { + return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); +}; +/*\ + * Snap.closestPoint + [ method ] + ** + * Returns closest point to a given one on a given path. + > Parameters + - path (Element) path element + - x (number) x coord of a point + - y (number) y coord of a point + = (object) in format + { + x (number) x coord of the point on the path + y (number) y coord of the point on the path + length (number) length of the path to the point + distance (number) distance from the given point to the path + } +\*/ +// Copied from http://bl.ocks.org/mbostock/8027637 +Snap.closestPoint = function (path, x, y) { + function distance2(p) { + var dx = p.x - x, + dy = p.y - y; + return dx * dx + dy * dy; + } + var pathNode = path.node, + pathLength = pathNode.getTotalLength(), + precision = pathLength / pathNode.pathSegList.numberOfItems * .125, + best, + bestLength, + bestDistance = Infinity; + + // linear scan for coarse approximation + for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { + if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) { + best = scan, bestLength = scanLength, bestDistance = scanDistance; + } + } + + // binary search for precise estimate + precision *= .5; + while (precision > .5) { + var before, + after, + beforeLength, + afterLength, + beforeDistance, + afterDistance; + if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) { + best = before, bestLength = beforeLength, bestDistance = beforeDistance; + } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) { + best = after, bestLength = afterLength, bestDistance = afterDistance; + } else { + precision *= .5; + } + } + + best = { + x: best.x, + y: best.y, + length: bestLength, + distance: Math.sqrt(bestDistance) + }; + return best; +} +/*\ + * Snap.is + [ method ] + ** + * Handy replacement for the `typeof` operator + - o (…) any object or primitive + - type (string) name of the type, e.g., `string`, `function`, `number`, etc. + = (boolean) `true` if given value is of given type +\*/ +Snap.is = is; +/*\ + * Snap.snapTo + [ method ] + ** + * Snaps given value to given grid + - values (array|number) given array of values or step of the grid + - value (number) value to adjust + - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`. + = (number) adjusted value +\*/ +Snap.snapTo = function (values, value, tolerance) { + tolerance = is(tolerance, "finite") ? tolerance : 10; + if (is(values, "array")) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; +}; +// Colour +/*\ + * Snap.getRGB + [ method ] + ** + * Parses color string as RGB object + - color (string) color string in one of the following formats: + # <ul> + # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li> + # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li> + # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li> + # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li> + # <li>rgba(•••, •••, •••, •••) — also with opacity</li> + # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li> + # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li> + # <li>hsba(•••, •••, •••, •••) — also with opacity</li> + # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li> + # <li>hsla(•••, •••, •••, •••) — also with opacity</li> + # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li> + # </ul> + * Note that `%` can be used any time: `rgb(20%, 255, 50%)`. + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) true if string can't be parsed + o } +\*/ +Snap.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + if (!colour) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsl2rgb(red, green, blue, opacity); + } + red = mmin(math.round(red), 255); + green = mmin(math.round(green), 255); + blue = mmin(math.round(blue), 255); + opacity = mmin(mmax(opacity, 0), 1); + rgb = {r: red, g: green, b: blue, toString: rgbtoString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + rgb.opacity = is(opacity, "finite") ? opacity : 1; + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; +}, Snap); +/*\ + * Snap.hsb + [ method ] + ** + * Converts HSB values to a hex representation of the color + - h (number) hue + - s (number) saturation + - b (number) value or brightness + = (string) hex representation of the color +\*/ +Snap.hsb = cacher(function (h, s, b) { + return Snap.hsb2rgb(h, s, b).hex; +}); +/*\ + * Snap.hsl + [ method ] + ** + * Converts HSL values to a hex representation of the color + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (string) hex representation of the color +\*/ +Snap.hsl = cacher(function (h, s, l) { + return Snap.hsl2rgb(h, s, l).hex; +}); +/*\ + * Snap.rgb + [ method ] + ** + * Converts RGB values to a hex representation of the color + - r (number) red + - g (number) green + - b (number) blue + = (string) hex representation of the color +\*/ +Snap.rgb = cacher(function (r, g, b, o) { + if (is(o, "finite")) { + var round = math.round; + return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")"; + } + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); +}); +var toHex = function (color) { + var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0], + red = "rgb(255, 0, 0)"; + toHex = cacher(function (color) { + if (color.toLowerCase() == "red") { + return red; + } + i.style.color = red; + i.style.color = color; + var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + return out == red ? null : out; + }); + return toHex(color); +}, +hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; +}, +hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; +}, +rgbtoString = function () { + return this.opacity == 1 || this.opacity == null ? + this.hex : + "rgba(" + [this.r, this.g, this.b, this.opacity] + ")"; +}, +prepareRGB = function (r, g, b) { + if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && is(r, string)) { + var clr = Snap.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; +}, +packageRGB = function (r, g, b, o) { + r = math.round(r * 255); + g = math.round(g * 255); + b = math.round(b * 255); + var rgb = { + r: r, + g: g, + b: b, + opacity: is(o, "finite") ? o : 1, + hex: Snap.rgb(r, g, b), + toString: rgbtoString + }; + is(o, "finite") && (rgb.opacity = o); + return rgb; +}; +/*\ + * Snap.color + [ method ] + ** + * Parses the color string and returns an object featuring the color's component values + - clr (string) color string in one of the supported formats (see @Snap.getRGB) + = (object) Combined RGB/HSB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) `true` if string can't be parsed, + o h (number) hue, + o s (number) saturation, + o v (number) value (brightness), + o l (number) lightness + o } +\*/ +Snap.color = function (clr) { + var rgb; + if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = Snap.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = Snap.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else { + if (is(clr, "string")) { + clr = Snap.getRGB(clr); + } + if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) { + rgb = Snap.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = Snap.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + clr.error = 1; + } + } + clr.toString = rgbtoString; + return clr; +}; +/*\ + * Snap.hsb2rgb + [ method ] + ** + * Converts HSB values to an RGB object + - h (number) hue + - s (number) saturation + - v (number) value or brightness + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsb2rgb = function (h, s, v, o) { + if (is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + o = h.o; + h = h.h; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.hsl2rgb + [ method ] + ** + * Converts HSL values to an RGB object + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsl2rgb = function (h, s, l, o) { + if (is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.rgb2hsb + [ method ] + ** + * Converts RGB values to an HSB object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSB object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o b (number) brightness + o } +\*/ +Snap.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; +}; +/*\ + * Snap.rgb2hsl + [ method ] + ** + * Converts RGB values to an HSL object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSL object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o l (number) luminosity + o } +\*/ +Snap.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; +}; + +// Transformations +/*\ + * Snap.parsePathString + [ method ] + ** + * Utility method + ** + * Parses given path string into an array of arrays of path segments + - pathString (string|array) path string or array of segments (in the last case it is returned straight away) + = (array) array of segments +\*/ +Snap.parsePathString = function (pathString) { + if (!pathString) { + return null; + } + var pth = Snap.path(pathString); + if (pth.arr) { + return Snap.path.clone(pth.arr); + } + + var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0}, + data = []; + if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption + data = Snap.path.clone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b].concat(params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "o" && params.length == 1) { + data.push([b, params[0]]); + } + if (name == "r") { + data.push([b].concat(params)); + } else while (params.length >= paramCounts[name]) { + data.push([b].concat(params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = Snap.path.toString; + pth.arr = Snap.path.clone(data); + return data; +}; +/*\ + * Snap.parseTransformString + [ method ] + ** + * Utility method + ** + * Parses given transform string into an array of transformations + - TString (string|array) transform string or array of transformations (in the last case it is returned straight away) + = (array) array of transformations +\*/ +var parseTransformString = Snap.parseTransformString = function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (is(TString, "array") && is(TString[0], "array")) { // rough assumption + data = Snap.path.clone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b].concat(params)); + }); + } + data.toString = Snap.path.toString; + return data; +}; +function svgTransform2string(tstr) { + var res = []; + tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) { + params = params.split(/\s*,\s*|\s+/); + if (name == "rotate" && params.length == 1) { + params.push(0, 0); + } + if (name == "scale") { + if (params.length > 2) { + params = params.slice(0, 2); + } else if (params.length == 2) { + params.push(0, 0); + } + if (params.length == 1) { + params.push(params[0], 0, 0); + } + } + if (name == "skewX") { + res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]); + } else if (name == "skewY") { + res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]); + } else { + res.push([name.charAt(0)].concat(params)); + } + return all; + }); + return res; +} +Snap._.svgTransform2string = svgTransform2string; +Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i; +function transform2matrix(tstr, bbox) { + var tdata = parseTransformString(tstr), + m = new Snap.Matrix; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 2){ + m.translate(t[1], 0); + } else if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || bbox; + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || bbox; + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.scale(t[1], t[1], x2, y2); + } else { + m.scale(t[1], t[1], t[2], t[3]); + } + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + } + } + return m; +} +Snap._.transform2matrix = transform2matrix; +Snap._unit2px = unit2px; +var contains = glob.doc.contains || glob.doc.compareDocumentPosition ? + function (a, b) { + var adown = a.nodeType == 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a == bup || !!(bup && bup.nodeType == 1 && ( + adown.contains ? + adown.contains(bup) : + a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16 + )); + } : + function (a, b) { + if (b) { + while (b) { + b = b.parentNode; + if (b == a) { + return true; + } + } + } + return false; + }; +function getSomeDefs(el) { + var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) || + (el.node.parentNode && wrap(el.node.parentNode)) || + Snap.select("svg") || + Snap(0, 0), + pdefs = p.select("defs"), + defs = pdefs == null ? false : pdefs.node; + if (!defs) { + defs = make("defs", p.node).node; + } + return defs; +} +function getSomeSVG(el) { + return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg"); +} +Snap._.getSomeDefs = getSomeDefs; +Snap._.getSomeSVG = getSomeSVG; +function unit2px(el, name, value) { + var svg = getSomeSVG(el).node, + out = {}, + mgr = svg.querySelector(".svg---mgr"); + if (!mgr) { + mgr = $("rect"); + $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"}); + svg.appendChild(mgr); + } + function getW(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {width: val}); + try { + return mgr.getBBox().width; + } catch (e) { + return 0; + } + } + function getH(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {height: val}); + try { + return mgr.getBBox().height; + } catch (e) { + return 0; + } + } + function set(nam, f) { + if (name == null) { + out[nam] = f(el.attr(nam) || 0); + } else if (nam == name) { + out = f(value == null ? el.attr(nam) || 0 : value); + } + } + switch (el.type) { + case "rect": + set("rx", getW); + set("ry", getH); + case "image": + set("width", getW); + set("height", getH); + case "text": + set("x", getW); + set("y", getH); + break; + case "circle": + set("cx", getW); + set("cy", getH); + set("r", getW); + break; + case "ellipse": + set("cx", getW); + set("cy", getH); + set("rx", getW); + set("ry", getH); + break; + case "line": + set("x1", getW); + set("x2", getW); + set("y1", getH); + set("y2", getH); + break; + case "marker": + set("refX", getW); + set("markerWidth", getW); + set("refY", getH); + set("markerHeight", getH); + break; + case "radialGradient": + set("fx", getW); + set("fy", getH); + break; + case "tspan": + set("dx", getW); + set("dy", getH); + break; + default: + set(name, getW); + } + svg.removeChild(mgr); + return out; +} +/*\ + * Snap.select + [ method ] + ** + * Wraps a DOM element specified by CSS selector as @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.select = function (query) { + query = Str(query).replace(/([^\\]):/g, "$1\\:"); + return wrap(glob.doc.querySelector(query)); +}; +/*\ + * Snap.selectAll + [ method ] + ** + * Wraps DOM elements specified by CSS selector as set or array of @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.selectAll = function (query) { + var nodelist = glob.doc.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; +}; + +function add2group(list) { + if (!is(list, "array")) { + list = Array.prototype.slice.call(arguments, 0); + } + var i = 0, + j = 0, + node = this.node; + while (this[i]) delete this[i++]; + for (i = 0; i < list.length; i++) { + if (list[i].type == "set") { + list[i].forEach(function (el) { + node.appendChild(el.node); + }); + } else { + node.appendChild(list[i].node); + } + } + var children = node.childNodes; + for (i = 0; i < children.length; i++) { + this[j++] = wrap(children[i]); + } + return this; +} +// Hub garbage collector every 10s +setInterval(function () { + for (var key in hub) if (hub[has](key)) { + var el = hub[key], + node = el.node; + if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) { + delete hub[key]; + } + } +}, 1e4); +function Element(el) { + if (el.snap in hub) { + return hub[el.snap]; + } + var svg; + try { + svg = el.ownerSVGElement; + } catch(e) {} + /*\ + * Element.node + [ property (object) ] + ** + * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. + > Usage + | // draw a circle at coordinate 10,10 with radius of 10 + | var c = paper.circle(10, 10, 10); + | c.node.onclick = function () { + | c.attr("fill", "red"); + | }; + \*/ + this.node = el; + if (svg) { + this.paper = new Paper(svg); + } + /*\ + * Element.type + [ property (string) ] + ** + * SVG tag name of the given element. + \*/ + this.type = el.tagName || el.nodeName; + var id = this.id = ID(this); + this.anims = {}; + this._ = { + transform: [] + }; + el.snap = id; + hub[id] = this; + if (this.type == "g") { + this.add = add2group; + } + if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) { + for (var method in Paper.prototype) if (Paper.prototype[has](method)) { + this[method] = Paper.prototype[method]; + } + } +} + /*\ + * Element.attr + [ method ] + ** + * Gets or sets given attributes of the element. + ** + - params (object) contains key-value pairs of attributes you want to set + * or + - param (string) name of the attribute + = (Element) the current element + * or + = (string) value of attribute + > Usage + | el.attr({ + | fill: "#fc0", + | stroke: "#000", + | strokeWidth: 2, // CamelCase... + | "fill-opacity": 0.5, // or dash-separated names + | width: "*=2" // prefixed values + | }); + | console.log(el.attr("fill")); // #fc0 + * Prefixed values in format `"+=10"` supported. All four operations + * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+` + * and `-`: `"+=2em"`. + \*/ + Element.prototype.attr = function (params, value) { + var el = this, + node = el.node; + if (!params) { + if (node.nodeType != 1) { + return { + text: node.nodeValue + }; + } + var attr = node.attributes, + out = {}; + for (var i = 0, ii = attr.length; i < ii; i++) { + out[attr[i].nodeName] = attr[i].nodeValue; + } + return out; + } + if (is(params, "string")) { + if (arguments.length > 1) { + var json = {}; + json[params] = value; + params = json; + } else { + return eve("snap.util.getattr." + params, el).firstDefined(); + } + } + for (var att in params) { + if (params[has](att)) { + eve("snap.util.attr." + att, el, params[att]); + } + } + return el; + }; +/*\ + * Snap.parse + [ method ] + ** + * Parses SVG fragment and converts it into a @Fragment + ** + - svg (string) SVG string + = (Fragment) the @Fragment +\*/ +Snap.parse = function (svg) { + var f = glob.doc.createDocumentFragment(), + full = true, + div = glob.doc.createElement("div"); + svg = Str(svg); + if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) { + svg = "<svg>" + svg + "</svg>"; + full = false; + } + div.innerHTML = svg; + svg = div.getElementsByTagName("svg")[0]; + if (svg) { + if (full) { + f = svg; + } else { + while (svg.firstChild) { + f.appendChild(svg.firstChild); + } + } + } + return new Fragment(f); +}; +function Fragment(frag) { + this.node = frag; +} +/*\ + * Snap.fragment + [ method ] + ** + * Creates a DOM fragment from a given list of elements or strings + ** + - varargs (…) SVG string + = (Fragment) the @Fragment +\*/ +Snap.fragment = function () { + var args = Array.prototype.slice.call(arguments, 0), + f = glob.doc.createDocumentFragment(); + for (var i = 0, ii = args.length; i < ii; i++) { + var item = args[i]; + if (item.node && item.node.nodeType) { + f.appendChild(item.node); + } + if (item.nodeType) { + f.appendChild(item); + } + if (typeof item == "string") { + f.appendChild(Snap.parse(item).node); + } + } + return new Fragment(f); +}; + +function make(name, parent) { + var res = $(name); + parent.appendChild(res); + var el = wrap(res); + return el; +} +function Paper(w, h) { + var res, + desc, + defs, + proto = Paper.prototype; + if (w && w.tagName == "svg") { + if (w.snap in hub) { + return hub[w.snap]; + } + var doc = w.ownerDocument; + res = new Element(w); + desc = w.getElementsByTagName("desc")[0]; + defs = w.getElementsByTagName("defs")[0]; + if (!desc) { + desc = $("desc"); + desc.appendChild(doc.createTextNode("Created with Snap")); + res.node.appendChild(desc); + } + if (!defs) { + defs = $("defs"); + res.node.appendChild(defs); + } + res.defs = defs; + for (var key in proto) if (proto[has](key)) { + res[key] = proto[key]; + } + res.paper = res.root = res; + } else { + res = make("svg", glob.doc.body); + $(res.node, { + height: h, + version: 1.1, + width: w, + xmlns: xmlns + }); + } + return res; +} +function wrap(dom) { + if (!dom) { + return dom; + } + if (dom instanceof Element || dom instanceof Fragment) { + return dom; + } + if (dom.tagName && dom.tagName.toLowerCase() == "svg") { + return new Paper(dom); + } + if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") { + return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]); + } + return new Element(dom); +} + +Snap._.make = make; +Snap._.wrap = wrap; +/*\ + * Paper.el + [ method ] + ** + * Creates an element on paper with a given name and no attributes + ** + - name (string) tag name + - attr (object) attributes + = (Element) the current element + > Usage + | var c = paper.circle(10, 10, 10); // is the same as... + | var c = paper.el("circle").attr({ + | cx: 10, + | cy: 10, + | r: 10 + | }); + | // and the same as + | var c = paper.el("circle", { + | cx: 10, + | cy: 10, + | r: 10 + | }); +\*/ +Paper.prototype.el = function (name, attr) { + var el = make(name, this.node); + attr && el.attr(attr); + return el; +}; +/*\ + * Element.children + [ method ] + ** + * Returns array of all the children of the element. + = (array) array of Elements +\*/ +Element.prototype.children = function () { + var out = [], + ch = this.node.childNodes; + for (var i = 0, ii = ch.length; i < ii; i++) { + out[i] = Snap(ch[i]); + } + return out; +}; +function jsonFiller(root, o) { + for (var i = 0, ii = root.length; i < ii; i++) { + var item = { + type: root[i].type, + attr: root[i].attr() + }, + children = root[i].children(); + o.push(item); + if (children.length) { + jsonFiller(children, item.childNodes = []); + } + } +} +/*\ + * Element.toJSON + [ method ] + ** + * Returns object representation of the given element and all its children. + = (object) in format + o { + o type (string) this.type, + o attr (object) attributes map, + o childNodes (array) optional array of children in the same format + o } +\*/ +Element.prototype.toJSON = function () { + var out = []; + jsonFiller([this], out); + return out[0]; +}; +// default +eve.on("snap.util.getattr", function () { + var att = eve.nt(); + att = att.substring(att.lastIndexOf(".") + 1); + var css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css); + } else { + return $(this.node, att); + } +}); +var cssAttr = { + "alignment-baseline": 0, + "baseline-shift": 0, + "clip": 0, + "clip-path": 0, + "clip-rule": 0, + "color": 0, + "color-interpolation": 0, + "color-interpolation-filters": 0, + "color-profile": 0, + "color-rendering": 0, + "cursor": 0, + "direction": 0, + "display": 0, + "dominant-baseline": 0, + "enable-background": 0, + "fill": 0, + "fill-opacity": 0, + "fill-rule": 0, + "filter": 0, + "flood-color": 0, + "flood-opacity": 0, + "font": 0, + "font-family": 0, + "font-size": 0, + "font-size-adjust": 0, + "font-stretch": 0, + "font-style": 0, + "font-variant": 0, + "font-weight": 0, + "glyph-orientation-horizontal": 0, + "glyph-orientation-vertical": 0, + "image-rendering": 0, + "kerning": 0, + "letter-spacing": 0, + "lighting-color": 0, + "marker": 0, + "marker-end": 0, + "marker-mid": 0, + "marker-start": 0, + "mask": 0, + "opacity": 0, + "overflow": 0, + "pointer-events": 0, + "shape-rendering": 0, + "stop-color": 0, + "stop-opacity": 0, + "stroke": 0, + "stroke-dasharray": 0, + "stroke-dashoffset": 0, + "stroke-linecap": 0, + "stroke-linejoin": 0, + "stroke-miterlimit": 0, + "stroke-opacity": 0, + "stroke-width": 0, + "text-anchor": 0, + "text-decoration": 0, + "text-rendering": 0, + "unicode-bidi": 0, + "visibility": 0, + "word-spacing": 0, + "writing-mode": 0 +}; + +eve.on("snap.util.attr", function (value) { + var att = eve.nt(), + attr = {}; + att = att.substring(att.lastIndexOf(".") + 1); + attr[att] = value; + var style = att.replace(/-(\w)/gi, function (all, letter) { + return letter.toUpperCase(); + }), + css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + this.node.style[style] = value == null ? E : value; + } else { + $(this.node, attr); + } +}); +(function (proto) {}(Paper.prototype)); + +// simple ajax +/*\ + * Snap.ajax + [ method ] + ** + * Simple implementation of Ajax + ** + - url (string) URL + - postData (object|string) data for post request + - callback (function) callback + - scope (object) #optional scope of callback + * or + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback + = (XMLHttpRequest) the XMLHttpRequest object, just in case +\*/ +Snap.ajax = function (url, postData, callback, scope){ + var req = new XMLHttpRequest, + id = ID(); + if (req) { + if (is(postData, "function")) { + scope = callback; + callback = postData; + postData = null; + } else if (is(postData, "object")) { + var pd = []; + for (var key in postData) if (postData.hasOwnProperty(key)) { + pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key])); + } + postData = pd.join("&"); + } + req.open((postData ? "POST" : "GET"), url, true); + if (postData) { + req.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + if (callback) { + eve.once("snap.ajax." + id + ".0", callback); + eve.once("snap.ajax." + id + ".200", callback); + eve.once("snap.ajax." + id + ".304", callback); + } + req.onreadystatechange = function() { + if (req.readyState != 4) return; + eve("snap.ajax." + id + "." + req.status, scope, req); + }; + if (req.readyState == 4) { + return req; + } + req.send(postData); + return req; + } +}; +/*\ + * Snap.load + [ method ] + ** + * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX) + ** + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback +\*/ +Snap.load = function (url, callback, scope) { + Snap.ajax(url, function (req) { + var f = Snap.parse(req.responseText); + scope ? callback.call(scope, f) : callback(f); + }); +}; +var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; +}; +/*\ + * Snap.getElementByPoint + [ method ] + ** + * Returns you topmost element under given point. + ** + = (object) Snap element object + - x (number) x coordinate from the top left corner of the window + - y (number) y coordinate from the top left corner of the window + > Usage + | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); +\*/ +Snap.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = glob.doc.elementFromPoint(x, y); + if (glob.win.opera && target.tagName == "svg") { + var so = getOffset(target), + sr = target.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = target.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + return wrap(target); +}; +/*\ + * Snap.plugin + [ method ] + ** + * Let you write plugins. You pass in a function with five arguments, like this: + | Snap.plugin(function (Snap, Element, Paper, global, Fragment) { + | Snap.newmethod = function () {}; + | Element.prototype.newmethod = function () {}; + | Paper.prototype.newmethod = function () {}; + | }); + * Inside the function you have access to all main objects (and their + * prototypes). This allow you to extend anything you want. + ** + - f (function) your plugin body +\*/ +Snap.plugin = function (f) { + f(Snap, Element, Paper, glob, Fragment); +}; +glob.win.Snap = Snap; +return Snap; +}(window || this)); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var elproto = Element.prototype, + is = Snap.is, + Str = String, + unit2px = Snap._unit2px, + $ = Snap._.$, + make = Snap._.make, + getSomeDefs = Snap._.getSomeDefs, + has = "hasOwnProperty", + wrap = Snap._.wrap; + /*\ + * Element.getBBox + [ method ] + ** + * Returns the bounding box descriptor for the given element + ** + = (object) bounding box descriptor: + o { + o cx: (number) x of the center, + o cy: (number) x of the center, + o h: (number) height, + o height: (number) height, + o path: (string) path command for the box, + o r0: (number) radius of a circle that fully encloses the box, + o r1: (number) radius of the smallest circle that can be enclosed, + o r2: (number) radius of the largest circle that can be enclosed, + o vb: (string) box as a viewbox command, + o w: (number) width, + o width: (number) width, + o x2: (number) x of the right side, + o x: (number) x of the left side, + o y2: (number) y of the bottom edge, + o y: (number) y of the top edge + o } + \*/ + elproto.getBBox = function (isWithoutTransform) { + if (!Snap.Matrix || !Snap.path) { + return this.node.getBBox(); + } + var el = this, + m = new Snap.Matrix; + if (el.removed) { + return Snap._.box(); + } + while (el.type == "use") { + if (!isWithoutTransform) { + m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0)); + } + if (el.original) { + el = el.original; + } else { + var href = el.attr("xlink:href"); + el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1)); + } + } + var _ = el._, + pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt; + try { + if (isWithoutTransform) { + _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox()); + return Snap._.box(_.bboxwt); + } else { + el.realPath = pathfinder(el); + el.matrix = el.transform().localMatrix; + _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix))); + return Snap._.box(_.bbox); + } + } catch (e) { + // Firefox doesn’t give you bbox of hidden element + return Snap._.box(); + } + }; + var propString = function () { + return this.string; + }; + function extractTransform(el, tstr) { + if (tstr == null) { + var doReturn = true; + if (el.type == "linearGradient" || el.type == "radialGradient") { + tstr = el.node.getAttribute("gradientTransform"); + } else if (el.type == "pattern") { + tstr = el.node.getAttribute("patternTransform"); + } else { + tstr = el.node.getAttribute("transform"); + } + if (!tstr) { + return new Snap.Matrix; + } + tstr = Snap._.svgTransform2string(tstr); + } else { + if (!Snap._.rgTransform.test(tstr)) { + tstr = Snap._.svgTransform2string(tstr); + } else { + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || ""); + } + if (is(tstr, "array")) { + tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr); + } + el._.transform = tstr; + } + var m = Snap._.transform2matrix(tstr, el.getBBox(1)); + if (doReturn) { + return m; + } else { + el.matrix = m; + } + } + /*\ + * Element.transform + [ method ] + ** + * Gets or sets transformation of the element + ** + - tstr (string) transform string in Snap or SVG format + = (Element) the current element + * or + = (object) transformation descriptor: + o { + o string (string) transform string, + o globalMatrix (Matrix) matrix of all transformations applied to element or its parents, + o localMatrix (Matrix) matrix of transformations applied only to the element, + o diffMatrix (Matrix) matrix of difference between global and local transformations, + o global (string) global transformation as string, + o local (string) local transformation as string, + o toString (function) returns `string` property + o } + \*/ + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + var papa = this, + global = new Snap.Matrix(this.node.getCTM()), + local = extractTransform(this), + ms = [local], + m = new Snap.Matrix, + i, + localString = local.toTransformString(), + string = Str(local) == Str(this.matrix) ? + Str(_.transform) : localString; + while (papa.type != "svg" && (papa = papa.parent())) { + ms.push(extractTransform(papa)); + } + i = ms.length; + while (i--) { + m.add(ms[i]); + } + return { + string: string, + globalMatrix: global, + totalMatrix: m, + localMatrix: local, + diffMatrix: global.clone().add(local.invert()), + global: global.toTransformString(), + total: m.toTransformString(), + local: localString, + toString: propString + }; + } + if (tstr instanceof Snap.Matrix) { + this.matrix = tstr; + this._.transform = tstr.toTransformString(); + } else { + extractTransform(this, tstr); + } + + if (this.node) { + if (this.type == "linearGradient" || this.type == "radialGradient") { + $(this.node, {gradientTransform: this.matrix}); + } else if (this.type == "pattern") { + $(this.node, {patternTransform: this.matrix}); + } else { + $(this.node, {transform: this.matrix}); + } + } + + return this; + }; + /*\ + * Element.parent + [ method ] + ** + * Returns the element's parent + ** + = (Element) the parent element + \*/ + elproto.parent = function () { + return wrap(this.node.parentNode); + }; + /*\ + * Element.append + [ method ] + ** + * Appends the given element to current one + ** + - el (Element|Set) element to append + = (Element) the parent element + \*/ + /*\ + * Element.add + [ method ] + ** + * See @Element.append + \*/ + elproto.append = elproto.add = function (el) { + if (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + it.add(el); + }); + return this; + } + el = wrap(el); + this.node.appendChild(el.node); + el.paper = this.paper; + } + return this; + }; + /*\ + * Element.appendTo + [ method ] + ** + * Appends the current element to the given one + ** + - el (Element) parent element to append to + = (Element) the child element + \*/ + elproto.appendTo = function (el) { + if (el) { + el = wrap(el); + el.append(this); + } + return this; + }; + /*\ + * Element.prepend + [ method ] + ** + * Prepends the given element to the current one + ** + - el (Element) element to prepend + = (Element) the parent element + \*/ + elproto.prepend = function (el) { + if (el) { + if (el.type == "set") { + var it = this, + first; + el.forEach(function (el) { + if (first) { + first.after(el); + } else { + it.prepend(el); + } + first = el; + }); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.insertBefore(el.node, this.node.firstChild); + this.add && this.add(); + el.paper = this.paper; + this.parent() && this.parent().add(); + parent && parent.add(); + } + return this; + }; + /*\ + * Element.prependTo + [ method ] + ** + * Prepends the current element to the given one + ** + - el (Element) parent element to prepend to + = (Element) the child element + \*/ + elproto.prependTo = function (el) { + el = wrap(el); + el.prepend(this); + return this; + }; + /*\ + * Element.before + [ method ] + ** + * Inserts given element before the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.before = function (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + var parent = el.parent(); + it.node.parentNode.insertBefore(el.node, it.node); + parent && parent.add(); + }); + this.parent().add(); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.parentNode.insertBefore(el.node, this.node); + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.after + [ method ] + ** + * Inserts given element after the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.after = function (el) { + el = wrap(el); + var parent = el.parent(); + if (this.node.nextSibling) { + this.node.parentNode.insertBefore(el.node, this.node.nextSibling); + } else { + this.node.parentNode.appendChild(el.node); + } + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.insertBefore + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertBefore = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.insertAfter + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertAfter = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node.nextSibling); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.remove + [ method ] + ** + * Removes element from the DOM + = (Element) the detached element + \*/ + elproto.remove = function () { + var parent = this.parent(); + this.node.parentNode && this.node.parentNode.removeChild(this.node); + delete this.paper; + this.removed = true; + parent && parent.add(); + return this; + }; + /*\ + * Element.select + [ method ] + ** + * Gathers the nested @Element matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Element) result of query selection + \*/ + elproto.select = function (query) { + return wrap(this.node.querySelector(query)); + }; + /*\ + * Element.selectAll + [ method ] + ** + * Gathers nested @Element objects matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Set|array) result of query selection + \*/ + elproto.selectAll = function (query) { + var nodelist = this.node.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; + }; + /*\ + * Element.asPX + [ method ] + ** + * Returns given attribute of the element as a `px` value (not %, em, etc.) + ** + - attr (string) attribute name + - value (string) #optional attribute value + = (Element) result of query selection + \*/ + elproto.asPX = function (attr, value) { + if (value == null) { + value = this.attr(attr); + } + return +unit2px(this, attr, value); + }; + // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar. + /*\ + * Element.use + [ method ] + ** + * Creates a `<use>` element linked to the current element + ** + = (Element) the `<use>` element + \*/ + elproto.use = function () { + var use, + id = this.node.id; + if (!id) { + id = this.id; + $(this.node, { + id: id + }); + } + if (this.type == "linearGradient" || this.type == "radialGradient" || + this.type == "pattern") { + use = make(this.type, this.node.parentNode); + } else { + use = make("use", this.node.parentNode); + } + $(use.node, { + "xlink:href": "#" + id + }); + use.original = this; + return use; + }; + function fixids(el) { + var els = el.selectAll("*"), + it, + url = /^\s*url\(("|'|)(.*)\1\)\s*$/, + ids = [], + uses = {}; + function urltest(it, name) { + var val = $(it.node, name); + val = val && val.match(url); + val = val && val[2]; + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + var attr = {}; + attr[name] = URL(id); + $(it.node, attr); + }); + } + } + function linktest(it) { + var val = $(it.node, "xlink:href"); + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + it.attr("xlink:href", "#" + id); + }); + } + } + for (var i = 0, ii = els.length; i < ii; i++) { + it = els[i]; + urltest(it, "fill"); + urltest(it, "stroke"); + urltest(it, "filter"); + urltest(it, "mask"); + urltest(it, "clip-path"); + linktest(it); + var oldid = $(it.node, "id"); + if (oldid) { + $(it.node, {id: it.id}); + ids.push({ + old: oldid, + id: it.id + }); + } + } + for (i = 0, ii = ids.length; i < ii; i++) { + var fs = uses[ids[i].old]; + if (fs) { + for (var j = 0, jj = fs.length; j < jj; j++) { + fs[j](ids[i].id); + } + } + } + } + /*\ + * Element.clone + [ method ] + ** + * Creates a clone of the element and inserts it after the element + ** + = (Element) the clone + \*/ + elproto.clone = function () { + var clone = wrap(this.node.cloneNode(true)); + if ($(clone.node, "id")) { + $(clone.node, {id: clone.id}); + } + fixids(clone); + clone.insertAfter(this); + return clone; + }; + /*\ + * Element.toDefs + [ method ] + ** + * Moves element to the shared `<defs>` area + ** + = (Element) the element + \*/ + elproto.toDefs = function () { + var defs = getSomeDefs(this); + defs.appendChild(this.node); + return this; + }; + /*\ + * Element.toPattern + [ method ] + ** + * Creates a `<pattern>` element from the current element + ** + * To create a pattern you have to specify the pattern rect: + - x (string|number) + - y (string|number) + - width (string|number) + - height (string|number) + = (Element) the `<pattern>` element + * You can use pattern later on as an argument for `fill` attribute: + | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({ + | fill: "none", + | stroke: "#bada55", + | strokeWidth: 5 + | }).pattern(0, 0, 10, 10), + | c = paper.circle(200, 200, 100); + | c.attr({ + | fill: p + | }); + \*/ + elproto.pattern = elproto.toPattern = function (x, y, width, height) { + var p = make("pattern", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + $(p.node, { + x: x, + y: y, + width: width, + height: height, + patternUnits: "userSpaceOnUse", + id: p.id, + viewBox: [x, y, width, height].join(" ") + }); + p.node.appendChild(this.node); + return p; + }; +// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path. +// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values? + /*\ + * Element.marker + [ method ] + ** + * Creates a `<marker>` element from the current element + ** + * To create a marker you have to specify the bounding rect and reference point: + - x (number) + - y (number) + - width (number) + - height (number) + - refX (number) + - refY (number) + = (Element) the `<marker>` element + * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end. + \*/ + // TODO add usage for markers + elproto.marker = function (x, y, width, height, refX, refY) { + var p = make("marker", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + refX = x.refX || x.cx; + refY = x.refY || x.cy; + x = x.x; + } + $(p.node, { + viewBox: [x, y, width, height].join(" "), + markerWidth: width, + markerHeight: height, + orient: "auto", + refX: refX || 0, + refY: refY || 0, + id: p.id + }); + p.node.appendChild(this.node); + return p; + }; + // animation + function slice(from, to, f) { + return function (arr) { + var res = arr.slice(from, to); + if (res.length == 1) { + res = res[0]; + } + return f ? f(res) : res; + }; + } + var Animation = function (attr, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + this.attr = attr; + this.dur = ms; + easing && (this.easing = easing); + callback && (this.callback = callback); + }; + Snap._.Animation = Animation; + /*\ + * Snap.animation + [ method ] + ** + * Creates an animation object + ** + - attr (object) attributes of final destination + - duration (number) duration of the animation, in milliseconds + - easing (function) #optional one of easing functions of @mina or custom one + - callback (function) #optional callback function that fires when animation ends + = (object) animation object + \*/ + Snap.animation = function (attr, ms, easing, callback) { + return new Animation(attr, ms, easing, callback); + }; + /*\ + * Element.inAnim + [ method ] + ** + * Returns a set of animations that may be able to manipulate the current element + ** + = (object) in format: + o { + o anim (object) animation object, + o mina (object) @mina object, + o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + \*/ + elproto.inAnim = function () { + var el = this, + res = []; + for (var id in el.anims) if (el.anims[has](id)) { + (function (a) { + res.push({ + anim: new Animation(a._attrs, a.dur, a.easing, a._callback), + mina: a, + curStatus: a.status(), + status: function (val) { + return a.status(val); + }, + stop: function () { + a.stop(); + } + }); + }(el.anims[id])); + } + return res; + }; + /*\ + * Snap.animate + [ method ] + ** + * Runs generic animation of one number into another with a caring function + ** + - from (number|array) number or array of numbers + - to (number|array) number or array of numbers + - setter (function) caring function that accepts one number argument + - duration (number) duration, in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function to execute when animation ends + = (object) animation object in @mina format + o { + o id (string) animation id, consider it read-only, + o duration (function) gets or sets the duration of the animation, + o easing (function) easing, + o speed (function) gets or sets the speed of the animation, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + | var rect = Snap().rect(0, 0, 10, 10); + | Snap.animate(0, 10, function (val) { + | rect.attr({ + | x: val + | }); + | }, 1000); + | // in given context is equivalent to + | rect.animate({x: 10}, 1000); + \*/ + Snap.animate = function (from, to, setter, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + var now = mina.time(), + anim = mina(from, to, now, now + ms, mina.time, setter, easing); + callback && eve.once("mina.finish." + anim.id, callback); + return anim; + }; + /*\ + * Element.stop + [ method ] + ** + * Stops all the animations for the current element + ** + = (Element) the current element + \*/ + elproto.stop = function () { + var anims = this.inAnim(); + for (var i = 0, ii = anims.length; i < ii; i++) { + anims[i].stop(); + } + return this; + }; + /*\ + * Element.animate + [ method ] + ** + * Animates the given attributes of the element + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + = (Element) the current element + \*/ + elproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = attrs.dur; + attrs = attrs.attr; + } + var fkeys = [], tkeys = [], keys = {}, from, to, f, eq, + el = this; + for (var key in attrs) if (attrs[has](key)) { + if (el.equal) { + eq = el.equal(key, Str(attrs[key])); + from = eq.from; + to = eq.to; + f = eq.f; + } else { + from = +el.attr(key); + to = +attrs[key]; + } + var len = is(from, "array") ? from.length : 1; + keys[key] = slice(fkeys.length, fkeys.length + len, f); + fkeys = fkeys.concat(from); + tkeys = tkeys.concat(to); + } + var now = mina.time(), + anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) { + var attr = {}; + for (var key in keys) if (keys[has](key)) { + attr[key] = keys[key](val); + } + el.attr(attr); + }, easing); + el.anims[anim.id] = anim; + anim._attrs = attrs; + anim._callback = callback; + eve("snap.animcreated." + el.id, anim); + eve.once("mina.finish." + anim.id, function () { + delete el.anims[anim.id]; + callback && callback.call(el); + }); + eve.once("mina.stop." + anim.id, function () { + delete el.anims[anim.id]; + }); + return el; + }; + var eldata = {}; + /*\ + * Element.data + [ method ] + ** + * Adds or retrieves given value associated with given key. (Don’t confuse + * with `data-` attributes) + * + * See also @Element.removeData + - key (string) key to store data + - value (any) #optional value to store + = (object) @Element + * or, if value is not specified: + = (any) value + > Usage + | for (var i = 0, i < 5, i++) { + | paper.circle(10 + 15 * i, 10, 10) + | .attr({fill: "#000"}) + | .data("i", i) + | .click(function () { + | alert(this.data("i")); + | }); + | } + \*/ + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 0){ + eve("snap.data.get." + this.id, this, data, null); + return data; + } + if (arguments.length == 1) { + if (Snap.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("snap.data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("snap.data.set." + this.id, this, value, key); + return this; + }; + /*\ + * Element.removeData + [ method ] + ** + * Removes value associated with an element by given key. + * If key is not provided, removes all the data of the element. + - key (string) #optional key + = (object) @Element + \*/ + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + /*\ + * Element.outerSVG + [ method ] + ** + * Returns SVG code for the element, equivalent to HTML's `outerHTML`. + * + * See also @Element.innerSVG + = (string) SVG code for the element + \*/ + /*\ + * Element.toString + [ method ] + ** + * See @Element.outerSVG + \*/ + elproto.outerSVG = elproto.toString = toString(1); + /*\ + * Element.innerSVG + [ method ] + ** + * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML` + = (string) SVG code for the element + \*/ + elproto.innerSVG = toString(); + function toString(type) { + return function () { + var res = type ? "<" + this.type : "", + attr = this.node.attributes, + chld = this.node.childNodes; + if (type) { + for (var i = 0, ii = attr.length; i < ii; i++) { + res += " " + attr[i].name + '="' + + attr[i].value.replace(/"/g, '\\"') + '"'; + } + } + if (chld.length) { + type && (res += ">"); + for (i = 0, ii = chld.length; i < ii; i++) { + if (chld[i].nodeType == 3) { + res += chld[i].nodeValue; + } else if (chld[i].nodeType == 1) { + res += wrap(chld[i]).toString(); + } + } + type && (res += "</" + this.type + ">"); + } else { + type && (res += "/>"); + } + return res; + }; + } + elproto.toDataURL = function () { + if (window && window.btoa) { + var bb = this.getBBox(), + svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', { + x: +bb.x.toFixed(3), + y: +bb.y.toFixed(3), + width: +bb.width.toFixed(3), + height: +bb.height.toFixed(3), + contents: this.outerSVG() + }); + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg))); + } + }; + /*\ + * Fragment.select + [ method ] + ** + * See @Element.select + \*/ + Fragment.prototype.select = elproto.select; + /*\ + * Fragment.selectAll + [ method ] + ** + * See @Element.selectAll + \*/ + Fragment.prototype.selectAll = elproto.selectAll; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var objectToString = Object.prototype.toString, + Str = String, + math = Math, + E = ""; + function Matrix(a, b, c, d, e, f) { + if (b == null && objectToString.call(a) == "[object SVGMatrix]") { + this.a = a.a; + this.b = a.b; + this.c = a.c; + this.d = a.d; + this.e = a.e; + this.f = a.f; + return; + } + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + /*\ + * Matrix.add + [ method ] + ** + * Adds the given matrix to existing one + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - matrix (object) @Matrix + \*/ + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + return this; + }; + /*\ + * Matrix.invert + [ method ] + ** + * Returns an inverted version of the matrix + = (object) @Matrix + \*/ + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + /*\ + * Matrix.clone + [ method ] + ** + * Returns a copy of the matrix + = (object) @Matrix + \*/ + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + /*\ + * Matrix.translate + [ method ] + ** + * Translate the matrix + - x (number) horizontal offset distance + - y (number) vertical offset distance + \*/ + matrixproto.translate = function (x, y) { + return this.add(1, 0, 0, 1, x, y); + }; + /*\ + * Matrix.scale + [ method ] + ** + * Scales the matrix + - x (number) amount to be scaled, with `1` resulting in no change + - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.) + - cx (number) #optional horizontal origin point from which to scale + - cy (number) #optional vertical origin point from which to scale + * Default cx, cy is the middle point of the element. + \*/ + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + return this; + }; + /*\ + * Matrix.rotate + [ method ] + ** + * Rotates the matrix + - a (number) angle of rotation, in degrees + - x (number) horizontal origin point from which to rotate + - y (number) vertical origin point from which to rotate + \*/ + matrixproto.rotate = function (a, x, y) { + a = Snap.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + return this.add(1, 0, 0, 1, -x, -y); + }; + /*\ + * Matrix.x + [ method ] + ** + * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y + - x (number) + - y (number) + = (number) x + \*/ + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + /*\ + * Matrix.y + [ method ] + ** + * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x + - x (number) + - y (number) + = (number) y + \*/ + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + /*\ + * Matrix.determinant + [ method ] + ** + * Finds determinant of the given matrix. + = (number) determinant + \*/ + matrixproto.determinant = function () { + return this.a * this.d - this.b * this.c; + }; + /*\ + * Matrix.split + [ method ] + ** + * Splits matrix into primitive transformations + = (object) in format: + o dx (number) translation by x + o dy (number) translation by y + o scalex (number) scale by x + o scaley (number) scale by y + o shear (number) shear + o rotate (number) rotation in deg + o isSimple (boolean) could it be represented via simple transformations + \*/ + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + if (this.determinant() < 0) { + out.scalex = -out.scalex; + } + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = Snap.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = Snap.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + /*\ + * Matrix.toTransformString + [ method ] + ** + * Returns transform string that represents given matrix + = (string) transform string + \*/ + matrixproto.toTransformString = function (shorter) { + var s = shorter || this.split(); + if (!+s.shear.toFixed(9)) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + /*\ + * Snap.Matrix + [ method ] + ** + * Matrix constructor, extend on your own risk. + * To create matrices use @Snap.matrix. + \*/ + Snap.Matrix = Matrix; + /*\ + * Snap.matrix + [ method ] + ** + * Utility method + ** + * Returns a matrix based on the given parameters + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - svgMatrix (SVGMatrix) + = (object) @Matrix + \*/ + Snap.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var has = "hasOwnProperty", + make = Snap._.make, + wrap = Snap._.wrap, + is = Snap.is, + getSomeDefs = Snap._.getSomeDefs, + reURLValue = /^url\(#?([^)]+)\)$/, + $ = Snap._.$, + URL = Snap.url, + Str = String, + separator = Snap._.separator, + E = ""; + // Attributes event handlers + eve.on("snap.util.attr.mask", function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value.type == "mask") { + var mask = value; + } else { + mask = make("mask", getSomeDefs(this)); + mask.node.appendChild(value.node); + } + !mask.node.id && $(mask.node, { + id: mask.id + }); + $(this.node, { + mask: URL(mask.id) + }); + } + }); + (function (clipIt) { + eve.on("snap.util.attr.clip", clipIt); + eve.on("snap.util.attr.clip-path", clipIt); + eve.on("snap.util.attr.clipPath", clipIt); + }(function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value.type == "clipPath") { + var clip = value; + } else { + clip = make("clipPath", getSomeDefs(this)); + clip.node.appendChild(value.node); + !clip.node.id && $(clip.node, { + id: clip.id + }); + } + $(this.node, { + "clip-path": URL(clip.node.id || clip.id) + }); + } + })); + function fillStroke(name) { + return function (value) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1 && + (value.node.firstChild.tagName == "radialGradient" || + value.node.firstChild.tagName == "linearGradient" || + value.node.firstChild.tagName == "pattern")) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value instanceof Element) { + if (value.type == "radialGradient" || value.type == "linearGradient" + || value.type == "pattern") { + if (!value.node.id) { + $(value.node, { + id: value.id + }); + } + var fill = URL(value.node.id); + } else { + fill = value.attr(name); + } + } else { + fill = Snap.color(value); + if (fill.error) { + var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value); + if (grad) { + if (!grad.node.id) { + $(grad.node, { + id: grad.id + }); + } + fill = URL(grad.node.id); + } else { + fill = value; + } + } else { + fill = Str(fill); + } + } + var attrs = {}; + attrs[name] = fill; + $(this.node, attrs); + this.node.style[name] = E; + }; + } + eve.on("snap.util.attr.fill", fillStroke("fill")); + eve.on("snap.util.attr.stroke", fillStroke("stroke")); + var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i; + eve.on("snap.util.grad.parse", function parseGrad(string) { + string = Str(string); + var tokens = string.match(gradrg); + if (!tokens) { + return null; + } + var type = tokens[1], + params = tokens[2], + stops = tokens[3]; + params = params.split(/\s*,\s*/).map(function (el) { + return +el == el ? +el : el; + }); + if (params.length == 1 && params[0] == 0) { + params = []; + } + stops = stops.split("-"); + stops = stops.map(function (el) { + el = el.split(":"); + var out = { + color: el[0] + }; + if (el[1]) { + out.offset = parseFloat(el[1]); + } + return out; + }); + return { + type: type, + params: params, + stops: stops + }; + }); + + eve.on("snap.util.attr.d", function (value) { + eve.stop(); + if (is(value, "array") && is(value[0], "array")) { + value = Snap.path.toString.call(value); + } + value = Str(value); + if (value.match(/[ruo]/i)) { + value = Snap.path.toAbsolute(value); + } + $(this.node, {d: value}); + })(-1); + eve.on("snap.util.attr.#text", function (value) { + eve.stop(); + value = Str(value); + var txt = glob.doc.createTextNode(value); + while (this.node.firstChild) { + this.node.removeChild(this.node.firstChild); + } + this.node.appendChild(txt); + })(-1); + eve.on("snap.util.attr.path", function (value) { + eve.stop(); + this.attr({d: value}); + })(-1); + eve.on("snap.util.attr.class", function (value) { + eve.stop(); + this.node.className.baseVal = value; + })(-1); + eve.on("snap.util.attr.viewBox", function (value) { + var vb; + if (is(value, "object") && "x" in value) { + vb = [value.x, value.y, value.width, value.height].join(" "); + } else if (is(value, "array")) { + vb = value.join(" "); + } else { + vb = value; + } + $(this.node, { + viewBox: vb + }); + eve.stop(); + })(-1); + eve.on("snap.util.attr.transform", function (value) { + this.transform(value); + eve.stop(); + })(-1); + eve.on("snap.util.attr.r", function (value) { + if (this.type == "rect") { + eve.stop(); + $(this.node, { + rx: value, + ry: value + }); + } + })(-1); + eve.on("snap.util.attr.textpath", function (value) { + eve.stop(); + if (this.type == "text") { + var id, tp, node; + if (!value && this.textPath) { + tp = this.textPath; + while (tp.node.firstChild) { + this.node.appendChild(tp.node.firstChild); + } + tp.remove(); + delete this.textPath; + return; + } + if (is(value, "string")) { + var defs = getSomeDefs(this), + path = wrap(defs.parentNode).path(value); + defs.appendChild(path.node); + id = path.id; + path.attr({id: id}); + } else { + value = wrap(value); + if (value instanceof Element) { + id = value.attr("id"); + if (!id) { + id = value.id; + value.attr({id: id}); + } + } + } + if (id) { + tp = this.textPath; + node = this.node; + if (tp) { + tp.attr({"xlink:href": "#" + id}); + } else { + tp = $("textPath", { + "xlink:href": "#" + id + }); + while (node.firstChild) { + tp.appendChild(node.firstChild); + } + node.appendChild(tp); + this.textPath = wrap(tp); + } + } + } + })(-1); + eve.on("snap.util.attr.text", function (value) { + if (this.type == "text") { + var i = 0, + node = this.node, + tuner = function (chunk) { + var out = $("tspan"); + if (is(chunk, "array")) { + for (var i = 0; i < chunk.length; i++) { + out.appendChild(tuner(chunk[i])); + } + } else { + out.appendChild(glob.doc.createTextNode(chunk)); + } + out.normalize && out.normalize(); + return out; + }; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var tuned = tuner(value); + while (tuned.firstChild) { + node.appendChild(tuned.firstChild); + } + } + eve.stop(); + })(-1); + function setFontSize(value) { + eve.stop(); + if (value == +value) { + value += "px"; + } + this.node.style.fontSize = value; + } + eve.on("snap.util.attr.fontSize", setFontSize)(-1); + eve.on("snap.util.attr.font-size", setFontSize)(-1); + + + eve.on("snap.util.getattr.transform", function () { + eve.stop(); + return this.transform(); + })(-1); + eve.on("snap.util.getattr.textpath", function () { + eve.stop(); + return this.textPath; + })(-1); + // Markers + (function () { + function getter(end) { + return function () { + eve.stop(); + var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end); + if (style == "none") { + return style; + } else { + return Snap(glob.doc.getElementById(style.match(reURLValue)[1])); + } + }; + } + function setter(end) { + return function (value) { + eve.stop(); + var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1); + if (value == "" || !value) { + this.node.style[name] = "none"; + return; + } + if (value.type == "marker") { + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + } + this.node.style[name] = URL(id); + return; + } + }; + } + eve.on("snap.util.getattr.marker-end", getter("end"))(-1); + eve.on("snap.util.getattr.markerEnd", getter("end"))(-1); + eve.on("snap.util.getattr.marker-start", getter("start"))(-1); + eve.on("snap.util.getattr.markerStart", getter("start"))(-1); + eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1); + eve.on("snap.util.getattr.markerMid", getter("mid"))(-1); + eve.on("snap.util.attr.marker-end", setter("end"))(-1); + eve.on("snap.util.attr.markerEnd", setter("end"))(-1); + eve.on("snap.util.attr.marker-start", setter("start"))(-1); + eve.on("snap.util.attr.markerStart", setter("start"))(-1); + eve.on("snap.util.attr.marker-mid", setter("mid"))(-1); + eve.on("snap.util.attr.markerMid", setter("mid"))(-1); + }()); + eve.on("snap.util.getattr.r", function () { + if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) { + eve.stop(); + return $(this.node, "rx"); + } + })(-1); + function textExtract(node) { + var out = []; + var children = node.childNodes; + for (var i = 0, ii = children.length; i < ii; i++) { + var chi = children[i]; + if (chi.nodeType == 3) { + out.push(chi.nodeValue); + } + if (chi.tagName == "tspan") { + if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) { + out.push(chi.firstChild.nodeValue); + } else { + out.push(textExtract(chi)); + } + } + } + return out; + } + eve.on("snap.util.getattr.text", function () { + if (this.type == "text" || this.type == "tspan") { + eve.stop(); + var out = textExtract(this.node); + return out.length == 1 ? out[0] : out; + } + })(-1); + eve.on("snap.util.getattr.#text", function () { + return this.node.textContent; + })(-1); + eve.on("snap.util.getattr.viewBox", function () { + eve.stop(); + var vb = $(this.node, "viewBox"); + if (vb) { + vb = vb.split(separator); + return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.points", function () { + var p = $(this.node, "points"); + eve.stop(); + if (p) { + return p.split(separator); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.path", function () { + var p = $(this.node, "d"); + eve.stop(); + return p; + })(-1); + eve.on("snap.util.getattr.class", function () { + return this.node.className.baseVal; + })(-1); + function getFontSize() { + eve.stop(); + return this.node.style.fontSize; + } + eve.on("snap.util.getattr.fontSize", getFontSize)(-1); + eve.on("snap.util.getattr.font-size", getFontSize)(-1); +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var rgNotSpace = /\S+/g, + rgBadSpace = /[\t\r\n\f]/g, + rgTrim = /(^\s+|\s+$)/g, + Str = String, + elproto = Element.prototype; + /*\ + * Element.addClass + [ method ] + ** + * Adds given class name or list of class names to the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.addClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + + if (classes.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (!~pos) { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.removeClass + [ method ] + ** + * Removes given class name or list of class names from the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.removeClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + if (curClasses.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.hasClass + [ method ] + ** + * Checks if the element has a given class name in the list of class names applied to it. + - value (string) class name + ** + = (boolean) `true` if the element has given class + \*/ + elproto.hasClass = function (value) { + var elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || []; + return !!~curClasses.indexOf(value); + }; + /*\ + * Element.toggleClass + [ method ] + ** + * Add or remove one or more classes from the element, depending on either + * the class’s presence or the value of the `flag` argument. + - value (string) class name or space separated list of class names + - flag (boolean) value to determine whether the class should be added or removed + ** + = (Element) original element. + \*/ + elproto.toggleClass = function (value, flag) { + if (flag != null) { + if (flag) { + return this.addClass(value); + } else { + return this.removeClass(value); + } + } + var classes = (value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } else { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var operators = { + "+": function (x, y) { + return x + y; + }, + "-": function (x, y) { + return x - y; + }, + "/": function (x, y) { + return x / y; + }, + "*": function (x, y) { + return x * y; + } + }, + Str = String, + reUnit = /[a-z]+$/i, + reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/; + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + eve.on("snap.util.attr", function (val) { + var plus = Str(val).match(reAddon); + if (plus) { + var evnt = eve.nt(), + name = evnt.substring(evnt.lastIndexOf(".") + 1), + a = this.attr(name), + atr = {}; + eve.stop(); + var unit = plus[3] || "", + aUnit = a.match(reUnit), + op = operators[plus[1]]; + if (aUnit && aUnit == unit) { + val = op(parseFloat(a), +plus[2]); + } else { + a = this.asPX(name); + val = op(this.asPX(name), this.asPX(name, plus[2] + unit)); + } + if (isNaN(a) || isNaN(val)) { + return; + } + atr[name] = val; + this.attr(atr); + } + })(-10); + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this, + bplus = Str(b).match(reAddon); + if (bplus) { + eve.stop(); + var unit = bplus[3] || "", + aUnit = a.match(reUnit), + op = operators[bplus[1]]; + if (aUnit && aUnit == unit) { + return { + from: parseFloat(a), + to: op(parseFloat(a), +bplus[2]), + f: getUnit(aUnit) + }; + } else { + a = this.asPX(name); + return { + from: a, + to: op(a, this.asPX(name, bplus[2] + unit)), + f: getNumber + }; + } + } + })(-10); +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var proto = Paper.prototype, + is = Snap.is; + /*\ + * Paper.rect + [ method ] + * + * Draws a rectangle + ** + - x (number) x coordinate of the top left corner + - y (number) y coordinate of the top left corner + - width (number) width + - height (number) height + - rx (number) #optional horizontal radius for rounded corners, default is 0 + - ry (number) #optional vertical radius for rounded corners, default is rx or 0 + = (object) the `rect` element + ** + > Usage + | // regular rectangle + | var c = paper.rect(10, 10, 50, 50); + | // rectangle with rounded corners + | var c = paper.rect(40, 40, 50, 50, 10); + \*/ + proto.rect = function (x, y, w, h, rx, ry) { + var attr; + if (ry == null) { + ry = rx; + } + if (is(x, "object") && x == "[object Object]") { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + width: w, + height: h + }; + if (rx != null) { + attr.rx = rx; + attr.ry = ry; + } + } + return this.el("rect", attr); + }; + /*\ + * Paper.circle + [ method ] + ** + * Draws a circle + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - r (number) radius + = (object) the `circle` element + ** + > Usage + | var c = paper.circle(50, 50, 40); + \*/ + proto.circle = function (cx, cy, r) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr = { + cx: cx, + cy: cy, + r: r + }; + } + return this.el("circle", attr); + }; + + var preload = (function () { + function onerror() { + this.parentNode.removeChild(this); + } + return function (src, f) { + var img = glob.doc.createElement("img"), + body = glob.doc.body; + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(img); + img.onload = img.onerror = null; + body.removeChild(img); + }; + img.onerror = onerror; + body.appendChild(img); + img.src = src; + }; + }()); + + /*\ + * Paper.image + [ method ] + ** + * Places an image on the surface + ** + - src (string) URI of the source image + - x (number) x offset position + - y (number) y offset position + - width (number) width of the image + - height (number) height of the image + = (object) the `image` element + * or + = (object) Snap element object with type `image` + ** + > Usage + | var c = paper.image("apple.png", 10, 10, 80, 80); + \*/ + proto.image = function (src, x, y, width, height) { + var el = this.el("image"); + if (is(src, "object") && "src" in src) { + el.attr(src); + } else if (src != null) { + var set = { + "xlink:href": src, + preserveAspectRatio: "none" + }; + if (x != null && y != null) { + set.x = x; + set.y = y; + } + if (width != null && height != null) { + set.width = width; + set.height = height; + } else { + preload(src, function () { + Snap._.$(el.node, { + width: this.offsetWidth, + height: this.offsetHeight + }); + }); + } + Snap._.$(el.node, set); + } + return el; + }; + /*\ + * Paper.ellipse + [ method ] + ** + * Draws an ellipse + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - rx (number) horizontal radius + - ry (number) vertical radius + = (object) the `ellipse` element + ** + > Usage + | var c = paper.ellipse(50, 50, 40, 20); + \*/ + proto.ellipse = function (cx, cy, rx, ry) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr ={ + cx: cx, + cy: cy, + rx: rx, + ry: ry + }; + } + return this.el("ellipse", attr); + }; + // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier. + /*\ + * Paper.path + [ method ] + ** + * Creates a `<path>` element using the given string as the path's definition + - pathString (string) #optional path string in SVG format + * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example: + | "M10,20L30,40" + * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates. + * + # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p> + # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> + # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> + # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> + # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> + # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> + # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> + # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> + # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> + # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> + # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> + # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> + # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> + * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier. + * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point. + > Usage + | var c = paper.path("M10 10L90 90"); + | // draw a diagonal line: + | // move to 10,10, line to 90,90 + \*/ + proto.path = function (d) { + var attr; + if (is(d, "object") && !is(d, "array")) { + attr = d; + } else if (d) { + attr = {d: d}; + } + return this.el("path", attr); + }; + /*\ + * Paper.g + [ method ] + ** + * Creates a group element + ** + - varargs (…) #optional elements to nest within the group + = (object) the `g` element + ** + > Usage + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(c2, c1); // note that the order of elements is different + * or + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(); + | g.add(c2, c1); + \*/ + /*\ + * Paper.group + [ method ] + ** + * See @Paper.g + \*/ + proto.group = proto.g = function (first) { + var attr, + el = this.el("g"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.svg + [ method ] + ** + * Creates a nested SVG element. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `svg` element + ** + \*/ + proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) { + var attrs = {}; + if (is(x, "object") && y == null) { + attrs = x; + } else { + if (x != null) { + attrs.x = x; + } + if (y != null) { + attrs.y = y; + } + if (width != null) { + attrs.width = width; + } + if (height != null) { + attrs.height = height; + } + if (vbx != null && vby != null && vbw != null && vbh != null) { + attrs.viewBox = [vbx, vby, vbw, vbh]; + } + } + return this.el("svg", attrs); + }; + /*\ + * Paper.mask + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a mask. + ** + = (object) the `mask` element + ** + \*/ + proto.mask = function (first) { + var attr, + el = this.el("mask"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.ptrn + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a pattern. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `pattern` element + ** + \*/ + proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) { + if (is(x, "object")) { + var attr = x; + } else { + attr = {patternUnits: "userSpaceOnUse"}; + if (x) { + attr.x = x; + } + if (y) { + attr.y = y; + } + if (width != null) { + attr.width = width; + } + if (height != null) { + attr.height = height; + } + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } else { + attr.viewBox = [x || 0, y || 0, width || 0, height || 0]; + } + } + return this.el("pattern", attr); + }; + /*\ + * Paper.use + [ method ] + ** + * Creates a <use> element. + - id (string) @optional id of element to link + * or + - id (Element) @optional element to link + ** + = (object) the `use` element + ** + \*/ + proto.use = function (id) { + if (id != null) { + if (id instanceof Element) { + if (!id.attr("id")) { + id.attr({id: Snap._.id(id)}); + } + id = id.attr("id"); + } + if (String(id).charAt() == "#") { + id = id.substring(1); + } + return this.el("use", {"xlink:href": "#" + id}); + } else { + return Element.prototype.use.call(this); + } + }; + /*\ + * Paper.symbol + [ method ] + ** + * Creates a <symbol> element. + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + = (object) the `symbol` element + ** + \*/ + proto.symbol = function (vx, vy, vw, vh) { + var attr = {}; + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } + + return this.el("symbol", attr); + }; + /*\ + * Paper.text + [ method ] + ** + * Draws a text string + ** + - x (number) x coordinate position + - y (number) y coordinate position + - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements + = (object) the `text` element + ** + > Usage + | var t1 = paper.text(50, 50, "Snap"); + | var t2 = paper.text(50, 50, ["S","n","a","p"]); + | // Text path usage + | t1.attr({textpath: "M10,10L100,100"}); + | // or + | var pth = paper.path("M10,10L100,100"); + | t1.attr({textpath: pth}); + \*/ + proto.text = function (x, y, text) { + var attr = {}; + if (is(x, "object")) { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + text: text || "" + }; + } + return this.el("text", attr); + }; + /*\ + * Paper.line + [ method ] + ** + * Draws a line + ** + - x1 (number) x coordinate position of the start + - y1 (number) y coordinate position of the start + - x2 (number) x coordinate position of the end + - y2 (number) y coordinate position of the end + = (object) the `line` element + ** + > Usage + | var t1 = paper.line(50, 50, 100, 100); + \*/ + proto.line = function (x1, y1, x2, y2) { + var attr = {}; + if (is(x1, "object")) { + attr = x1; + } else if (x1 != null) { + attr = { + x1: x1, + x2: x2, + y1: y1, + y2: y2 + }; + } + return this.el("line", attr); + }; + /*\ + * Paper.polyline + [ method ] + ** + * Draws a polyline + ** + - points (array) array of points + * or + - varargs (…) points + = (object) the `polyline` element + ** + > Usage + | var p1 = paper.polyline([10, 10, 100, 100]); + | var p2 = paper.polyline(10, 10, 100, 100); + \*/ + proto.polyline = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polyline", attr); + }; + /*\ + * Paper.polygon + [ method ] + ** + * Draws a polygon. See @Paper.polyline + \*/ + proto.polygon = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polygon", attr); + }; + // gradients + (function () { + var $ = Snap._.$; + // gradients' helpers + function Gstops() { + return this.selectAll("stop"); + } + function GaddStop(color, offset) { + var stop = $("stop"), + attr = { + offset: +offset + "%" + }; + color = Snap.color(color); + attr["stop-color"] = color.hex; + if (color.opacity < 1) { + attr["stop-opacity"] = color.opacity; + } + $(stop, attr); + this.node.appendChild(stop); + return this; + } + function GgetBBox() { + if (this.type == "linearGradient") { + var x1 = $(this.node, "x1") || 0, + x2 = $(this.node, "x2") || 1, + y1 = $(this.node, "y1") || 0, + y2 = $(this.node, "y2") || 0; + return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1)); + } else { + var cx = this.node.cx || .5, + cy = this.node.cy || .5, + r = this.node.r || 0; + return Snap._.box(cx - r, cy - r, r * 2, r * 2); + } + } + function gradient(defs, str) { + var grad = eve("snap.util.grad.parse", null, str).firstDefined(), + el; + if (!grad) { + return null; + } + grad.params.unshift(defs); + if (grad.type.toLowerCase() == "l") { + el = gradientLinear.apply(0, grad.params); + } else { + el = gradientRadial.apply(0, grad.params); + } + if (grad.type != grad.type.toLowerCase()) { + $(el.node, { + gradientUnits: "userSpaceOnUse" + }); + } + var stops = grad.stops, + len = stops.length, + start = 0, + j = 0; + function seed(i, end) { + var step = (end - start) / (i - j); + for (var k = j; k < i; k++) { + stops[k].offset = +(+start + step * (k - j)).toFixed(2); + } + j = i; + start = end; + } + len--; + for (var i = 0; i < len; i++) if ("offset" in stops[i]) { + seed(i, stops[i].offset); + } + stops[len].offset = stops[len].offset || 100; + seed(len, stops[len].offset); + for (i = 0; i <= len; i++) { + var stop = stops[i]; + el.addStop(stop.color, stop.offset); + } + return el; + } + function gradientLinear(defs, x1, y1, x2, y2) { + var el = Snap._.make("linearGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (x1 != null) { + $(el.node, { + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }); + } + return el; + } + function gradientRadial(defs, cx, cy, r, fx, fy) { + var el = Snap._.make("radialGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (cx != null) { + $(el.node, { + cx: cx, + cy: cy, + r: r + }); + } + if (fx != null && fy != null) { + $(el.node, { + fx: fx, + fy: fy + }); + } + return el; + } + /*\ + * Paper.gradient + [ method ] + ** + * Creates a gradient element + ** + - gradient (string) gradient descriptor + > Gradient Descriptor + * The gradient descriptor is an expression formatted as + * follows: `<type>(<coords>)<colors>`. The `<type>` can be + * either linear or radial. The uppercase `L` or `R` letters + * indicate absolute coordinates offset from the SVG surface. + * Lowercase `l` or `r` letters indicate coordinates + * calculated relative to the element to which the gradient is + * applied. Coordinates specify a linear gradient vector as + * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`, + * `r` and optional `fx`, `fy` specifying a focal point away + * from the center of the circle. Specify `<colors>` as a list + * of dash-separated CSS color values. Each color may be + * followed by a custom offset value, separated with a colon + * character. + > Examples + * Linear gradient, relative from top-left corner to bottom-right + * corner, from black through red to white: + | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff"); + * Linear gradient, absolute from (0, 0) to (100, 100), from black + * through red at 25% to white: + | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff"); + * Radial gradient, relative from the center of the element with radius + * half the width, from black to white: + | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff"); + * To apply the gradient: + | paper.circle(50, 50, 40).attr({ + | fill: g + | }); + = (object) the `gradient` element + \*/ + proto.gradient = function (str) { + return gradient(this.defs, str); + }; + proto.gradientLinear = function (x1, y1, x2, y2) { + return gradientLinear(this.defs, x1, y1, x2, y2); + }; + proto.gradientRadial = function (cx, cy, r, fx, fy) { + return gradientRadial(this.defs, cx, cy, r, fx, fy); + }; + /*\ + * Paper.toString + [ method ] + ** + * Returns SVG code for the @Paper + = (string) SVG code for the @Paper + \*/ + proto.toString = function () { + var doc = this.node.ownerDocument, + f = doc.createDocumentFragment(), + d = doc.createElement("div"), + svg = this.node.cloneNode(true), + res; + f.appendChild(d); + d.appendChild(svg); + Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"}); + res = d.innerHTML; + f.removeChild(f.firstChild); + return res; + }; + /*\ + * Paper.toDataURL + [ method ] + ** + * Returns SVG code for the @Paper as Data URI string. + = (string) Data URI string + \*/ + proto.toDataURL = function () { + if (window && window.btoa) { + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this))); + } + }; + /*\ + * Paper.clear + [ method ] + ** + * Removes all child nodes of the paper, except <defs>. + \*/ + proto.clear = function () { + var node = this.node.firstChild, + next; + while (node) { + next = node.nextSibling; + if (node.tagName != "defs") { + node.parentNode.removeChild(node); + } else { + proto.clear.call({node: node}); + } + node = next; + } + }; + }()); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + is = Snap.is, + clone = Snap._.clone, + has = "hasOwnProperty", + p2s = /,?([a-z]),?/gi, + toFloat = parseFloat, + math = Math, + PI = math.PI, + mmin = math.min, + mmax = math.max, + pow = math.pow, + abs = math.abs; + function paths(ps) { + var p = paths.ps = paths.ps || {}; + if (p[ps]) { + p[ps].sleep = 100; + } else { + p[ps] = { + sleep: 100 + }; + } + setTimeout(function () { + for (var key in p) if (p[has](key) && key != ps) { + p[key].sleep--; + !p[key].sleep && delete p[key]; + } + }); + return p[ps]; + } + function box(x, y, width, height) { + if (x == null) { + x = y = width = height = 0; + } + if (y == null) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + return { + x: x, + y: y, + width: width, + w: width, + height: height, + h: height, + x2: x + width, + y2: y + height, + cx: x + width / 2, + cy: y + height / 2, + r1: math.min(width, height) / 2, + r2: math.max(width, height) / 2, + r0: math.sqrt(width * width + height * height) / 2, + path: rectPath(x, y, width, height), + vb: [x, y, width, height].join(" ") + }; + } + function toString() { + return this.join(",").replace(p2s, "$1"); + } + function pathClone(pathArray) { + var res = clone(pathArray); + res.toString = toString; + return res; + } + function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + if (length == null) { + return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + } else { + return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, + getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); + } + } + function getLengthFactory(istotal, subpath) { + function O(val) { + return +(+val).toFixed(3); + } + return Snap._.cacher(function (path, length, onlystart) { + if (path instanceof Element) { + path = path.attr("d"); + } + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += [ + "C" + O(point.start.x), + O(point.start.y), + O(point.m.x), + O(point.m.y), + O(point.x), + O(point.y) + ]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = [ + "M" + O(point.x), + O(point.y) + "C" + O(point.n.x), + O(point.n.y), + O(point.end.x), + O(point.end.y), + O(p[5]), + O(p[6]) + ].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return point; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + return point; + }, null, Snap._.clone); + } + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + // (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + } + function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + if (!Snap.is(p1x, "array")) { + p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; + } + var bbox = curveDim.apply(null, p1x); + return box( + bbox.min.x, + bbox.min.y, + bbox.max.x - bbox.min.x, + bbox.max.y - bbox.min.y + ); + } + function isPointInsideBBox(bbox, x, y) { + return x >= bbox.x && + x <= bbox.x + bbox.width && + y >= bbox.y && + y <= bbox.y + bbox.height; + } + function isBBoxIntersect(bbox1, bbox2) { + bbox1 = box(bbox1); + bbox2 = box(bbox2); + return isPointInsideBBox(bbox2, bbox1.x, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2) + || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x + || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) + && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y + || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); + } + function base3(t, p1, p2, p3, p4) { + var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, + t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; + return t * t2 - 3 * p1 + 3 * p2; + } + function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { + if (z == null) { + z = 1; + } + z = z > 1 ? 1 : z < 0 ? 0 : z; + var z2 = z / 2, + n = 12, + Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816], + Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], + sum = 0; + for (var i = 0; i < n; i++) { + var ct = z2 * Tvalues[i] + z2, + xbase = base3(ct, x1, x2, x3, x4), + ybase = base3(ct, y1, y2, y3, y4), + comb = xbase * xbase + ybase * ybase; + sum += Cvalues[i] * math.sqrt(comb); + } + return z2 * sum; + } + function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { + if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { + return; + } + var t = 1, + step = t / 2, + t2 = t - step, + l, + e = .01; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + while (abs(l - ll) > e) { + step /= 2; + t2 += (l < ll ? 1 : -1) * step; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + } + return t2; + } + function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { + if ( + mmax(x1, x2) < mmin(x3, x4) || + mmin(x1, x2) > mmax(x3, x4) || + mmax(y1, y2) < mmin(y3, y4) || + mmin(y1, y2) > mmax(y3, y4) + ) { + return; + } + var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), + ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), + denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + + if (!denominator) { + return; + } + var px = nx / denominator, + py = ny / denominator, + px2 = +px.toFixed(2), + py2 = +py.toFixed(2); + if ( + px2 < +mmin(x1, x2).toFixed(2) || + px2 > +mmax(x1, x2).toFixed(2) || + px2 < +mmin(x3, x4).toFixed(2) || + px2 > +mmax(x3, x4).toFixed(2) || + py2 < +mmin(y1, y2).toFixed(2) || + py2 > +mmax(y1, y2).toFixed(2) || + py2 < +mmin(y3, y4).toFixed(2) || + py2 > +mmax(y3, y4).toFixed(2) + ) { + return; + } + return {x: px, y: py}; + } + function inter(bez1, bez2) { + return interHelper(bez1, bez2); + } + function interCount(bez1, bez2) { + return interHelper(bez1, bez2, 1); + } + function interHelper(bez1, bez2, justCount) { + var bbox1 = bezierBBox(bez1), + bbox2 = bezierBBox(bez2); + if (!isBBoxIntersect(bbox1, bbox2)) { + return justCount ? 0 : []; + } + var l1 = bezlen.apply(0, bez1), + l2 = bezlen.apply(0, bez2), + n1 = ~~(l1 / 8), + n2 = ~~(l2 / 8), + dots1 = [], + dots2 = [], + xy = {}, + res = justCount ? 0 : []; + for (var i = 0; i < n1 + 1; i++) { + var p = findDotsAtSegment.apply(0, bez1.concat(i / n1)); + dots1.push({x: p.x, y: p.y, t: i / n1}); + } + for (i = 0; i < n2 + 1; i++) { + p = findDotsAtSegment.apply(0, bez2.concat(i / n2)); + dots2.push({x: p.x, y: p.y, t: i / n2}); + } + for (i = 0; i < n1; i++) { + for (var j = 0; j < n2; j++) { + var di = dots1[i], + di1 = dots1[i + 1], + dj = dots2[j], + dj1 = dots2[j + 1], + ci = abs(di1.x - di.x) < .001 ? "y" : "x", + cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", + is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); + if (is) { + if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { + continue; + } + xy[is.x.toFixed(4)] = is.y.toFixed(4); + var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), + t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); + if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) { + if (justCount) { + res++; + } else { + res.push({ + x: is.x, + y: is.y, + t1: t1, + t2: t2 + }); + } + } + } + } + } + return res; + } + function pathIntersection(path1, path2) { + return interPathHelper(path1, path2); + } + function pathIntersectionNumber(path1, path2) { + return interPathHelper(path1, path2, 1); + } + function interPathHelper(path1, path2, justCount) { + path1 = path2curve(path1); + path2 = path2curve(path2); + var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, + res = justCount ? 0 : []; + for (var i = 0, ii = path1.length; i < ii; i++) { + var pi = path1[i]; + if (pi[0] == "M") { + x1 = x1m = pi[1]; + y1 = y1m = pi[2]; + } else { + if (pi[0] == "C") { + bez1 = [x1, y1].concat(pi.slice(1)); + x1 = bez1[6]; + y1 = bez1[7]; + } else { + bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; + x1 = x1m; + y1 = y1m; + } + for (var j = 0, jj = path2.length; j < jj; j++) { + var pj = path2[j]; + if (pj[0] == "M") { + x2 = x2m = pj[1]; + y2 = y2m = pj[2]; + } else { + if (pj[0] == "C") { + bez2 = [x2, y2].concat(pj.slice(1)); + x2 = bez2[6]; + y2 = bez2[7]; + } else { + bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; + x2 = x2m; + y2 = y2m; + } + var intr = interHelper(bez1, bez2, justCount); + if (justCount) { + res += intr; + } else { + for (var k = 0, kk = intr.length; k < kk; k++) { + intr[k].segment1 = i; + intr[k].segment2 = j; + intr[k].bez1 = bez1; + intr[k].bez2 = bez2; + } + res = res.concat(intr); + } + } + } + } + } + return res; + } + function isPointInsidePath(path, x, y) { + var bbox = pathBBox(path); + return isPointInsideBBox(bbox, x, y) && + interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; + } + function pathBBox(path) { + var pth = paths(path); + if (pth.bbox) { + return clone(pth.bbox); + } + if (!path) { + return box(); + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X.concat(dim.min.x, dim.max.x); + Y = Y.concat(dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin.apply(0, X), + ymin = mmin.apply(0, Y), + xmax = mmax.apply(0, X), + ymax = mmax.apply(0, Y), + bb = box(xmin, ymin, xmax - xmin, ymax - ymin); + pth.bbox = clone(bb); + return bb; + } + function rectPath(x, y, w, h, r) { + if (r) { + return [ + ["M", +x + (+r), y], + ["l", w - r * 2, 0], + ["a", r, r, 0, 0, 1, r, r], + ["l", 0, h - r * 2], + ["a", r, r, 0, 0, 1, -r, r], + ["l", r * 2 - w, 0], + ["a", r, r, 0, 0, 1, -r, -r], + ["l", 0, r * 2 - h], + ["a", r, r, 0, 0, 1, r, -r], + ["z"] + ]; + } + var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + res.toString = toString; + return res; + } + function ellipsePath(x, y, rx, ry, a) { + if (a == null && ry == null) { + ry = rx; + } + x = +x; + y = +y; + rx = +rx; + ry = +ry; + if (a != null) { + var rad = Math.PI / 180, + x1 = x + rx * Math.cos(-ry * rad), + x2 = x + rx * Math.cos(-a * rad), + y1 = y + rx * Math.sin(-ry * rad), + y2 = y + rx * Math.sin(-a * rad), + res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]]; + } else { + res = [ + ["M", x, y], + ["m", 0, -ry], + ["a", rx, ry, 0, 1, 1, 0, 2 * ry], + ["a", rx, ry, 0, 1, 1, 0, -2 * ry], + ["z"] + ]; + } + res.toString = toString; + return res; + } + var unit2px = Snap._unit2px, + getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx, attr.cy, attr.r); + }, + ellipse: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry); + }, + rect: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry); + }, + image: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height); + }, + line: function (el) { + return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")]; + }, + polyline: function (el) { + return "M" + el.attr("points"); + }, + polygon: function (el) { + return "M" + el.attr("points") + "z"; + }, + deflt: function (el) { + var bbox = el.node.getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }; + function pathToRelative(pathArray) { + var pth = paths(pathArray), + lowerCase = String.prototype.toLowerCase; + if (pth.rel) { + return pathClone(pth.rel); + } + if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) { + pathArray = Snap.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = toString; + pth.rel = pathClone(res); + return res; + } + function pathToAbsolute(pathArray) { + var pth = paths(pathArray); + if (pth.abs) { + return pathClone(pth.abs); + } + if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption + pathArray = Snap.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0, + pa0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + var crz = pathArray.length == 3 && + pathArray[0][0] == "M" && + pathArray[1][0].toUpperCase() == "R" && + pathArray[2][0].toUpperCase() == "Z"; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + pa0 = pa[0]; + if (pa0 != pa0.toUpperCase()) { + r[0] = pa0.toUpperCase(); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +pa[6] + x; + r[7] = +pa[7] + y; + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y].concat(pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + break; + case "O": + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + break; + case "U": + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa0 == "R") { + dots = [x, y].concat(pa.slice(1)); + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + r = ["R"].concat(pa.slice(-2)); + } else if (pa0 == "O") { + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + } else if (pa0 == "U") { + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + pa0 = pa0.toUpperCase(); + if (pa0 != "O") { + switch (r[0]) { + case "Z": + x = +mx; + y = +my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + } + res.toString = toString; + pth.abs = pathClone(res); + return res; + } + function l2c(x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + } + function q2c(x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + } + function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = Snap._.cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4].concat(res); + } else { + res = [m2, m3, m4].concat(res).join().split(","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + } + function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + } + + // Returns bounding box of cubic bezier curve. + // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + // Original version: NISHIO Hirokazu + // Modifications: https://github.com/timo22345 + function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) { + var tvalues = [], + bounds = [[], []], + a, b, c, t, t1, t2, b2ac, sqrtb2ac; + for (var i = 0; i < 2; ++i) { + if (i == 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + if (abs(a) < 1e-12) { + if (abs(b) < 1e-12) { + continue; + } + t = -c / b; + if (0 < t && t < 1) { + tvalues.push(t); + } + continue; + } + b2ac = b * b - 4 * c * a; + sqrtb2ac = math.sqrt(b2ac); + if (b2ac < 0) { + continue; + } + t1 = (-b + sqrtb2ac) / (2 * a); + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + t2 = (-b - sqrtb2ac) / (2 * a); + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + var x, y, j = tvalues.length, + jlen = j, + mt; + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); + bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + + + return { + min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])}, + max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])} + }; + } + + function path2curve(path, path2) { + var pth = !path2 && paths(path); + if (!path2 && pth.curve) { + return pathClone(pth.curve); + } + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d, pcom) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); + break; + case "S": + if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. + nx = d.x * 2 - d.bx; // And reflect the previous + ny = d.y * 2 - d.by; // command's control point relative to the current point. + } + else { // or some else or nothing + nx = d.x; + ny = d.y; + } + path = ["C", nx, ny].concat(path.slice(1)); + break; + case "T": + if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. + d.qx = d.x * 2 - d.qx; // And make a reflection similar + d.qy = d.y * 2 - d.qy; // to case "S". + } + else { // or something else or nothing + d.qx = d.x; + d.qy = d.y; + } + path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"].concat(l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"].concat(l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"].concat(l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved + p2 && (pcoms2[i] = "A"); // the same as above + pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + pcoms1 = [], // path commands of original path p + pcoms2 = [], // path commands of original path p2 + pfirst = "", // temporary holder for original path command + pcom = ""; // holder for previous path command of original path + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] && (pfirst = p[i][0]); // save current path command + + if (pfirst != "C") // C is not saved yet, because it may be result of conversion + { + pcoms1[i] = pfirst; // Save current path command + i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom + } + p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath + + if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command + // which may produce multiple C:s + // so we have to make sure that C is also C in original path + + fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 + + if (p2) { // the same procedures is done to p2 + p2[i] && (pfirst = p2[i][0]); + if (pfirst != "C") { + pcoms2[i] = pfirst; + i && (pcom = pcoms2[i - 1]); + } + p2[i] = processPath(p2[i], attrs2, pcom); + + if (pcoms2[i] != "A" && pfirst == "C") { + pcoms2[i] = "C"; + } + + fixArc(p2, i); + } + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + if (!p2) { + pth.curve = pathClone(p); + } + return p2 ? [p, p2] : p; + } + function mapPath(path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + } + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 == i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 == i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 == i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + // export + Snap.path = paths; + + /*\ + * Snap.path.getTotalLength + [ method ] + ** + * Returns the length of the given path in pixels + ** + - path (string) SVG path string + ** + = (number) length + \*/ + Snap.path.getTotalLength = getTotalLength; + /*\ + * Snap.path.getPointAtLength + [ method ] + ** + * Returns the coordinates of the point located at the given length along the given path + ** + - path (string) SVG path string + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + Snap.path.getPointAtLength = getPointAtLength; + /*\ + * Snap.path.getSubpath + [ method ] + ** + * Returns the subpath of a given path between given start and end lengths + ** + - path (string) SVG path string + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + Snap.path.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + /*\ + * Element.getTotalLength + [ method ] + ** + * Returns the length of the path in pixels (only works for `path` elements) + = (number) length + \*/ + elproto.getTotalLength = function () { + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + }; + // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length? + /*\ + * Element.getPointAtLength + [ method ] + ** + * Returns coordinates of the point located at the given length on the given path (only works for `path` elements) + ** + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + elproto.getPointAtLength = function (length) { + return getPointAtLength(this.attr("d"), length); + }; + // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear. + /*\ + * Element.getSubpath + [ method ] + ** + * Returns subpath of a given element from given start and end lengths (only works for `path` elements) + ** + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + elproto.getSubpath = function (from, to) { + return Snap.path.getSubpath(this.attr("d"), from, to); + }; + Snap._.box = box; + /*\ + * Snap.path.findDotsAtSegment + [ method ] + ** + * Utility method + ** + * Finds dot coordinates on the given cubic beziér curve at the given t + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + - t (number) position on the curve (0..1) + = (object) point information in format: + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o m: { + o x: (number) x coordinate of the left anchor, + o y: (number) y coordinate of the left anchor + o }, + o n: { + o x: (number) x coordinate of the right anchor, + o y: (number) y coordinate of the right anchor + o }, + o start: { + o x: (number) x coordinate of the start of the curve, + o y: (number) y coordinate of the start of the curve + o }, + o end: { + o x: (number) x coordinate of the end of the curve, + o y: (number) y coordinate of the end of the curve + o }, + o alpha: (number) angle of the curve derivative at the point + o } + \*/ + Snap.path.findDotsAtSegment = findDotsAtSegment; + /*\ + * Snap.path.bezierBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given cubic beziér curve + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + * or + - bez (array) array of six points for beziér curve + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.bezierBBox = bezierBBox; + /*\ + * Snap.path.isPointInsideBBox + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside bounding box + - bbox (string) bounding box + - x (string) x coordinate of the point + - y (string) y coordinate of the point + = (boolean) `true` if point is inside + \*/ + Snap.path.isPointInsideBBox = isPointInsideBBox; + Snap.closest = function (x, y, X, Y) { + var r = 100, + b = box(x - r / 2, y - r / 2, r, r), + inside = [], + getter = X[0].hasOwnProperty("x") ? function (i) { + return { + x: X[i].x, + y: X[i].y + }; + } : function (i) { + return { + x: X[i], + y: Y[i] + }; + }, + found = 0; + while (r <= 1e6 && !found) { + for (var i = 0, ii = X.length; i < ii; i++) { + var xy = getter(i); + if (isPointInsideBBox(b, xy.x, xy.y)) { + found++; + inside.push(xy); + break; + } + } + if (!found) { + r *= 2; + b = box(x - r / 2, y - r / 2, r, r) + } + } + if (r == 1e6) { + return; + } + var len = Infinity, + res; + for (i = 0, ii = inside.length; i < ii; i++) { + var l = Snap.len(x, y, inside[i].x, inside[i].y); + if (len > l) { + len = l; + inside[i].len = l; + res = inside[i]; + } + } + return res; + }; + /*\ + * Snap.path.isBBoxIntersect + [ method ] + ** + * Utility method + ** + * Returns `true` if two bounding boxes intersect + - bbox1 (string) first bounding box + - bbox2 (string) second bounding box + = (boolean) `true` if bounding boxes intersect + \*/ + Snap.path.isBBoxIntersect = isBBoxIntersect; + /*\ + * Snap.path.intersection + [ method ] + ** + * Utility method + ** + * Finds intersections of two paths + - path1 (string) path string + - path2 (string) path string + = (array) dots of intersection + o [ + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o t1: (number) t value for segment of path1, + o t2: (number) t value for segment of path2, + o segment1: (number) order number for segment of path1, + o segment2: (number) order number for segment of path2, + o bez1: (array) eight coordinates representing beziér curve for the segment of path1, + o bez2: (array) eight coordinates representing beziér curve for the segment of path2 + o } + o ] + \*/ + Snap.path.intersection = pathIntersection; + Snap.path.intersectionNumber = pathIntersectionNumber; + /*\ + * Snap.path.isPointInside + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside a given closed path. + * + * Note: fill mode doesn’t affect the result of this method. + - path (string) path string + - x (number) x of the point + - y (number) y of the point + = (boolean) `true` if point is inside the path + \*/ + Snap.path.isPointInside = isPointInsidePath; + /*\ + * Snap.path.getBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given path + - path (string) path string + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.getBBox = pathBBox; + Snap.path.get = getPath; + /*\ + * Snap.path.toRelative + [ method ] + ** + * Utility method + ** + * Converts path coordinates into relative values + - path (string) path string + = (array) path string + \*/ + Snap.path.toRelative = pathToRelative; + /*\ + * Snap.path.toAbsolute + [ method ] + ** + * Utility method + ** + * Converts path coordinates into absolute values + - path (string) path string + = (array) path string + \*/ + Snap.path.toAbsolute = pathToAbsolute; + /*\ + * Snap.path.toCubic + [ method ] + ** + * Utility method + ** + * Converts path to a new path where all segments are cubic beziér curves + - pathString (string|array) path string or array of segments + = (array) array of segments + \*/ + Snap.path.toCubic = path2curve; + /*\ + * Snap.path.map + [ method ] + ** + * Transform the path string with the given matrix + - path (string) path string + - matrix (object) see @Matrix + = (string) transformed path string + \*/ + Snap.path.map = mapPath; + Snap.path.toString = toString; + Snap.path.clone = pathClone; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var mmax = Math.max, + mmin = Math.min; + + // Set + var Set = function (items) { + this.items = []; + this.bindings = {}; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i]) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + /*\ + * Set.push + [ method ] + ** + * Adds each argument to the current set + = (object) original element + \*/ + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + /*\ + * Set.pop + [ method ] + ** + * Removes last element and returns it + = (object) element + \*/ + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + /*\ + * Set.forEach + [ method ] + ** + * Executes given function for each element in the set + * + * If the function returns `false`, the loop stops running. + ** + - callback (function) function to run + - thisArg (object) context object for the callback + = (object) Set object + \*/ + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + /*\ + * Set.animate + [ method ] + ** + * Animates each element in set in sync. + * + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + * or + - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]` + > Usage + | // animate all elements in set to radius 10 + | set.animate({r: 10}, 500, mina.easein); + | // or + | // animate first element to radius 10, but second to radius 20 and in different time + | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]); + = (Element) the current element + \*/ + setproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Snap._.Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = easing.dur; + attrs = attrs.attr; + } + var args = arguments; + if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) { + var each = true; + } + var begin, + handler = function () { + if (begin) { + this.b = begin; + } else { + begin = this.b; + } + }, + cb = 0, + set = this, + callbacker = callback && function () { + if (++cb == set.length) { + callback.call(this); + } + }; + return this.forEach(function (el, i) { + eve.once("snap.animcreated." + el.id, handler); + if (each) { + args[i] && el.animate.apply(el, args[i]); + } else { + el.animate(attrs, ms, easing, callbacker); + } + }); + }; + setproto.remove = function () { + while (this.length) { + this.pop().remove(); + } + return this; + }; + /*\ + * Set.bind + [ method ] + ** + * Specifies how to handle a specific attribute when applied + * to a set. + * + ** + - attr (string) attribute name + - callback (function) function to run + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + - eattr (string) attribute on the element to bind the attribute to + = (object) Set object + \*/ + setproto.bind = function (attr, a, b) { + var data = {}; + if (typeof a == "function") { + this.bindings[attr] = a; + } else { + var aname = b || attr; + this.bindings[attr] = function (v) { + data[aname] = v; + a.attr(data); + }; + } + return this; + }; + setproto.attr = function (value) { + var unbound = {}; + for (var k in value) { + if (this.bindings[k]) { + this.bindings[k](value[k]); + } else { + unbound[k] = value[k]; + } + } + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(unbound); + } + return this; + }; + /*\ + * Set.clear + [ method ] + ** + * Removes all elements from the set + \*/ + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + /*\ + * Set.splice + [ method ] + ** + * Removes range of elements from the set + ** + - index (number) position of the deletion + - count (number) number of element to remove + - insertion… (object) #optional elements to insert + = (object) set elements that were deleted + \*/ + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + /*\ + * Set.exclude + [ method ] + ** + * Removes given element from the set + ** + - element (object) element to remove + = (boolean) `true` if object was found and removed from the set + \*/ + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + return false; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + x2 = [], + y2 = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + x2.push(box.x + box.width); + y2.push(box.y + box.height); + } + x = mmin.apply(0, x); + y = mmin.apply(0, y); + x2 = mmax.apply(0, x2); + y2 = mmax.apply(0, y2); + return { + x: x, + y: y, + x2: x2, + y2: y2, + width: x2 - x, + height: y2 - y, + cx: x + (x2 - x) / 2, + cy: y + (y2 - y) / 2 + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Snap\u2018s set"; + }; + setproto.type = "set"; + // export + Snap.Set = Set; + Snap.set = function () { + var set = new Set; + if (arguments.length) { + set.push.apply(set, Array.prototype.slice.call(arguments, 0)); + } + return set; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var names = {}, + reUnit = /[a-z]+$/i, + Str = String; + names.stroke = names.fill = "colour"; + function getEmpty(item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + } + function equaliseTransform(t1, t2, getBBox) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = Snap.parseTransformString(t1) || []; + t2 = Snap.parseTransformString(t2) || []; + var maxlength = Math.max(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + t1 = Snap._.transform2matrix(t1, getBBox()); + t2 = Snap._.transform2matrix(t2, getBBox()); + from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]]; + to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]]; + break; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: path2array(from), + to: path2array(to), + f: getPath(from) + }; + } + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + function getViewBox(val) { + return val.join(" "); + } + function getColour(clr) { + return Snap.rgb(clr[0], clr[1], clr[2]); + } + function getPath(path) { + var k = 0, i, ii, j, jj, out, a, b = []; + for (i = 0, ii = path.length; i < ii; i++) { + out = "["; + a = ['"' + path[i][0] + '"']; + for (j = 1, jj = path[i].length; j < jj; j++) { + a[j] = "val[" + (k++) + "]"; + } + out += a + "]"; + b[i] = out; + } + return Function("val", "return Snap.path.toString.call([" + b + "])"); + } + function path2array(path) { + var out = []; + for (var i = 0, ii = path.length; i < ii; i++) { + for (var j = 1, jj = path[i].length; j < jj; j++) { + out.push(path[i][j]); + } + } + return out; + } + function isNumeric(obj) { + return isFinite(parseFloat(obj)); + } + function arrayEqual(arr1, arr2) { + if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) { + return false; + } + return arr1.toString() == arr2.toString(); + } + Element.prototype.equal = function (name, b) { + return eve("snap.util.equal", this, name, b).firstDefined(); + }; + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this; + if (isNumeric(a) && isNumeric(b)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getNumber + }; + } + if (names[name] == "colour") { + A = Snap.color(a); + B = Snap.color(b); + return { + from: [A.r, A.g, A.b, A.opacity], + to: [B.r, B.g, B.b, B.opacity], + f: getColour + }; + } + if (name == "viewBox") { + A = this.attr(name).vb.split(" ").map(Number); + B = b.split(" ").map(Number); + return { + from: A, + to: B, + f: getViewBox + }; + } + if (name == "transform" || name == "gradientTransform" || name == "patternTransform") { + if (b instanceof Snap.Matrix) { + b = b.toTransformString(); + } + if (!Snap._.rgTransform.test(b)) { + b = Snap._.svgTransform2string(b); + } + return equaliseTransform(a, b, function () { + return el.getBBox(1); + }); + } + if (name == "d" || name == "path") { + A = Snap.path.toCubic(a, b); + return { + from: path2array(A[0]), + to: path2array(A[1]), + f: getPath(A[0]) + }; + } + if (name == "points") { + A = Str(a).split(Snap._.separator); + B = Str(b).split(Snap._.separator); + return { + from: A, + to: B, + f: function (val) { return val; } + }; + } + var aUnit = a.match(reUnit), + bUnit = Str(b).match(reUnit); + if (aUnit && arrayEqual(aUnit, bUnit)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getUnit(aUnit) + }; + } else { + return { + from: this.asPX(name), + to: this.asPX(name, b), + f: getNumber + }; + } + }); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + has = "hasOwnProperty", + supportsTouch = "createTouch" in glob.doc, + events = [ + "click", "dblclick", "mousedown", "mousemove", "mouseout", + "mouseover", "mouseup", "touchstart", "touchmove", "touchend", + "touchcancel" + ], + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + getScroll = function (xy, el) { + var name = xy == "y" ? "scrollTop" : "scrollLeft", + doc = el && el.node ? el.node.ownerDocument : glob.doc; + return doc[name in doc.documentElement ? "documentElement" : "body"][name]; + }, + preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = getScroll("y", element), + scrollX = getScroll("x", element); + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + var x = e.clientX + scrollX, + y = e.clientY + scrollY; + return fn.call(element, e, x, y); + }; + + if (type !== realName) { + obj.addEventListener(type, f, false); + } + + obj.addEventListener(realName, f, false); + + return function () { + if (type !== realName) { + obj.removeEventListener(type, f, false); + } + + obj.removeEventListener(realName, f, false); + return true; + }; + }, + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = getScroll("y"), + scrollX = getScroll("x"), + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches && e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + // glob.win.opera && parent.removeChild(node); + // node.style.display = "none"; + // o = dragi.el.paper.getElementByPoint(x, y); + // node.style.display = display; + // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + Snap.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + eve.off("snap.drag.*." + dragi.el.id); + } + drag = []; + }; + /*\ + * Element.click + [ method ] + ** + * Adds a click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unclick + [ method ] + ** + * Removes a click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.dblclick + [ method ] + ** + * Adds a double click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.undblclick + [ method ] + ** + * Removes a double click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousedown + [ method ] + ** + * Adds a mousedown event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousedown + [ method ] + ** + * Removes a mousedown event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousemove + [ method ] + ** + * Adds a mousemove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousemove + [ method ] + ** + * Removes a mousemove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseout + [ method ] + ** + * Adds a mouseout event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseout + [ method ] + ** + * Removes a mouseout event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseover + [ method ] + ** + * Adds a mouseover event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseover + [ method ] + ** + * Removes a mouseover event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseup + [ method ] + ** + * Adds a mouseup event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseup + [ method ] + ** + * Removes a mouseup event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchstart + [ method ] + ** + * Adds a touchstart event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchstart + [ method ] + ** + * Removes a touchstart event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchmove + [ method ] + ** + * Adds a touchmove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchmove + [ method ] + ** + * Removes a touchmove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchend + [ method ] + ** + * Adds a touchend event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchend + [ method ] + ** + * Removes a touchend event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchcancel + [ method ] + ** + * Adds a touchcancel event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchcancel + [ method ] + ** + * Removes a touchcancel event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + for (var i = events.length; i--;) { + (function (eventName) { + Snap[eventName] = elproto[eventName] = function (fn, scope) { + if (Snap.is(fn, "function")) { + this.events = this.events || []; + this.events.push({ + name: eventName, + f: fn, + unbind: addEvent(this.node || document, eventName, fn, scope || this) + }); + } else { + for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) { + try { + this.events[i].f.call(this); + } catch (e) {} + } + } + return this; + }; + Snap["un" + eventName] = + elproto["un" + eventName] = function (fn) { + var events = this.events || [], + l = events.length; + while (l--) if (events[l].name == eventName && + (events[l].f == fn || !fn)) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + /*\ + * Element.hover + [ method ] + ** + * Adds hover event handlers to the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + - icontext (object) #optional context for hover in handler + - ocontext (object) #optional context for hover out handler + = (object) @Element + \*/ + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + /*\ + * Element.unhover + [ method ] + ** + * Removes hover event handlers from the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + = (object) @Element + \*/ + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture. + // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from? + // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason. + // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID? + /*\ + * Element.drag + [ method ] + ** + * Adds event handlers for an element's drag gesture + ** + - onmove (function) handler for moving + - onstart (function) handler for drag start + - onend (function) handler for drag end + - mcontext (object) #optional context for moving handler + - scontext (object) #optional context for drag start handler + - econtext (object) #optional context for drag end handler + * Additionaly following `drag` events are triggered: `drag.start.<id>` on start, + * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element + * `drag.over.<id>` fires as well. + * + * Start event and start handler are called in specified context or in context of the element with following parameters: + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * Move event and move handler are called in specified context or in context of the element with following parameters: + o dx (number) shift by x from the start point + o dy (number) shift by y from the start point + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * End event and end handler are called in specified context or in context of the element with following parameters: + o event (object) DOM event object + = (object) @Element + \*/ + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + var el = this; + if (!arguments.length) { + var origTransform; + return el.drag(function (dx, dy) { + this.attr({ + transform: origTransform + (origTransform ? "T" : "t") + [dx, dy] + }); + }, function () { + origTransform = this.transform().local; + }); + } + function start(e, x, y) { + (e.originalEvent || e).preventDefault(); + el._drag.x = x; + el._drag.y = y; + el._drag.id = e.identifier; + !drag.length && Snap.mousemove(dragMove).mouseup(dragUp); + drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("snap.drag.start." + el.id, onstart); + onmove && eve.on("snap.drag.move." + el.id, onmove); + onend && eve.on("snap.drag.end." + el.id, onend); + eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e); + } + function init(e, x, y) { + eve("snap.draginit." + el.id, el, e, x, y); + } + eve.on("snap.draginit." + el.id, start); + el._drag = {}; + draggable.push({el: el, start: start, init: init}); + el.mousedown(init); + return el; + }; + /* + * Element.onDragOver + [ method ] + ** + * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id) + - f (function) handler for event, first argument would be the element you are dragging over + \*/ + // elproto.onDragOver = function (f) { + // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id); + // }; + /*\ + * Element.undrag + [ method ] + ** + * Removes all drag event handlers from the given element + \*/ + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].init); + draggable.splice(i, 1); + eve.unbind("snap.drag.*." + this.id); + eve.unbind("snap.draginit." + this.id); + } + !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp); + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + pproto = Paper.prototype, + rgurl = /^\s*url\((.+)\)/, + Str = String, + $ = Snap._.$; + Snap.filter = {}; + /*\ + * Paper.filter + [ method ] + ** + * Creates a `<filter>` element + ** + - filstr (string) SVG fragment of filter provided as a string + = (object) @Element + * Note: It is recommended to use filters embedded into the page inside an empty SVG element. + > Usage + | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + pproto.filter = function (filstr) { + var paper = this; + if (paper.type != "svg") { + paper = paper.paper; + } + var f = Snap.parse(Str(filstr)), + id = Snap._.id(), + width = paper.node.offsetWidth, + height = paper.node.offsetHeight, + filter = $("filter"); + $(filter, { + id: id, + filterUnits: "userSpaceOnUse" + }); + filter.appendChild(f.node); + paper.defs.appendChild(filter); + return new Element(filter); + }; + + eve.on("snap.util.getattr.filter", function () { + eve.stop(); + var p = $(this.node, "filter"); + if (p) { + var match = Str(p).match(rgurl); + return match && Snap.select(match[1]); + } + }); + eve.on("snap.util.attr.filter", function (value) { + if (value instanceof Element && value.type == "filter") { + eve.stop(); + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + id = value.id; + } + $(this.node, { + filter: Snap.url(id) + }); + } + if (!value || value == "none") { + eve.stop(); + this.node.removeAttribute("filter"); + } + }); + /*\ + * Snap.filter.blur + [ method ] + ** + * Returns an SVG markup string for the blur filter + ** + - x (number) amount of horizontal blur, in pixels + - y (number) #optional amount of vertical blur, in pixels + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.blur(5, 10)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.blur = function (x, y) { + if (x == null) { + x = 2; + } + var def = y == null ? x : [x, y]; + return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', { + def: def + }); + }; + Snap.filter.blur.toString = function () { + return this(); + }; + /*\ + * Snap.filter.shadow + [ method ] + ** + * Returns an SVG markup string for the shadow filter + ** + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - blur (number) #optional amount of blur + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * which makes blur default to `4`. Or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - opacity (number) #optional `0..1` opacity of the shadow + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.shadow(0, 2, 3)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.shadow = function (dx, dy, blur, color, opacity) { + if (typeof blur == "string") { + color = blur; + opacity = color; + blur = 4; + } + if (typeof color != "string") { + opacity = color; + color = "#000"; + } + color = color || "#000"; + if (blur == null) { + blur = 4; + } + if (opacity == null) { + opacity = 1; + } + if (dx == null) { + dx = 0; + dy = 2; + } + if (dy == null) { + dy = dx; + } + color = Snap.color(color); + return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', { + color: color, + dx: dx, + dy: dy, + blur: blur, + opacity: opacity + }); + }; + Snap.filter.shadow.toString = function () { + return this(); + }; + /*\ + * Snap.filter.grayscale + [ method ] + ** + * Returns an SVG markup string for the grayscale filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.grayscale = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', { + a: 0.2126 + 0.7874 * (1 - amount), + b: 0.7152 - 0.7152 * (1 - amount), + c: 0.0722 - 0.0722 * (1 - amount), + d: 0.2126 - 0.2126 * (1 - amount), + e: 0.7152 + 0.2848 * (1 - amount), + f: 0.0722 - 0.0722 * (1 - amount), + g: 0.2126 - 0.2126 * (1 - amount), + h: 0.0722 + 0.9278 * (1 - amount) + }); + }; + Snap.filter.grayscale.toString = function () { + return this(); + }; + /*\ + * Snap.filter.sepia + [ method ] + ** + * Returns an SVG markup string for the sepia filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.sepia = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', { + a: 0.393 + 0.607 * (1 - amount), + b: 0.769 - 0.769 * (1 - amount), + c: 0.189 - 0.189 * (1 - amount), + d: 0.349 - 0.349 * (1 - amount), + e: 0.686 + 0.314 * (1 - amount), + f: 0.168 - 0.168 * (1 - amount), + g: 0.272 - 0.272 * (1 - amount), + h: 0.534 - 0.534 * (1 - amount), + i: 0.131 + 0.869 * (1 - amount) + }); + }; + Snap.filter.sepia.toString = function () { + return this(); + }; + /*\ + * Snap.filter.saturate + [ method ] + ** + * Returns an SVG markup string for the saturate filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.saturate = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', { + amount: 1 - amount + }); + }; + Snap.filter.saturate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.hueRotate + [ method ] + ** + * Returns an SVG markup string for the hue-rotate filter + ** + - angle (number) angle of rotation + = (string) filter representation + \*/ + Snap.filter.hueRotate = function (angle) { + angle = angle || 0; + return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', { + angle: angle + }); + }; + Snap.filter.hueRotate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.invert + [ method ] + ** + * Returns an SVG markup string for the invert filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.invert = function (amount) { + if (amount == null) { + amount = 1; + } +// <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" color-interpolation-filters="sRGB"/> + return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: 1 - amount + }); + }; + Snap.filter.invert.toString = function () { + return this(); + }; + /*\ + * Snap.filter.brightness + [ method ] + ** + * Returns an SVG markup string for the brightness filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.brightness = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', { + amount: amount + }); + }; + Snap.filter.brightness.toString = function () { + return this(); + }; + /*\ + * Snap.filter.contrast + [ method ] + ** + * Returns an SVG markup string for the contrast filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.contrast = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: .5 - amount / 2 + }); + }; + Snap.filter.contrast.toString = function () { + return this(); + }; +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var box = Snap._.box, + is = Snap.is, + firstLetter = /^[^a-z]*([tbmlrc])/i, + toString = function () { + return "T" + this.dx + "," + this.dy; + }; + /*\ + * Element.getAlign + [ method ] + ** + * Returns shift needed to align the element relatively to given element. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string + > Usage + | el.transform(el.getAlign(el2, "top")); + * or + | var dy = el.getAlign(el2, "top").dy; + \*/ + Element.prototype.getAlign = function (el, way) { + if (way == null && is(el, "string")) { + way = el; + el = null; + } + el = el || this.paper; + var bx = el.getBBox ? el.getBBox() : box(el), + bb = this.getBBox(), + out = {}; + way = way && way.match(firstLetter); + way = way ? way[1].toLowerCase() : "c"; + switch (way) { + case "t": + out.dx = 0; + out.dy = bx.y - bb.y; + break; + case "b": + out.dx = 0; + out.dy = bx.y2 - bb.y2; + break; + case "m": + out.dx = 0; + out.dy = bx.cy - bb.cy; + break; + case "l": + out.dx = bx.x - bb.x; + out.dy = 0; + break; + case "r": + out.dx = bx.x2 - bb.x2; + out.dy = 0; + break; + default: + out.dx = bx.cx - bb.cx; + out.dy = 0; + break; + } + out.toString = toString; + return out; + }; + /*\ + * Element.align + [ method ] + ** + * Aligns the element relatively to given one via transformation. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object) this element + > Usage + | el.align(el2, "top"); + * or + | el.align("middle"); + \*/ + Element.prototype.align = function (el, way) { + return this.transform("..." + this.getAlign(el, way)); + }; +}); + +return Snap; +})); diff --git a/web/pgadmin/misc/templates/explain/js/explain.js b/web/pgadmin/misc/templates/explain/js/explain.js new file mode 100644 index 0000000..911e107 --- /dev/null +++ b/web/pgadmin/misc/templates/explain/js/explain.js @@ -0,0 +1,688 @@ +define ( + 'pgadmin.misc.explain', + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'backbone', 'snap.svg'], + function($, _, S, pgAdmin, Backbone, Snap) { + +pgAdmin = pgAdmin || window.pgAdmin || {}; +var pgExplain = pgAdmin.Explain; + +// Snap.svg plug-in to write multitext as image name +Snap.plugin(function (Snap, Element, Paper, glob) { + Paper.prototype.multitext = function (x, y, txt, max_width, attributes) { + var svg = Snap(), + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + isWordBroken = false, + temp = svg.text(0, 0, abc); + + temp.attr(attributes); + + /* + * Find letter width in pixels and + * index from where the text should be broken + */ + var letter_width = temp.getBBox().width / abc.length, + word_break_index = Math.round((max_width / letter_width)) - 1; + + svg.remove(); + + var words = txt.split(" "), + width_so_far = 0, + lines=[], curr_line = '', + /* + * Function to divide string into multiple lines + * and store them in an array if it size crosses + * the max-width boundary. + */ + splitTextInMultiLine = function(leading, so_far, line) { + var l = line.length, + res = []; + + if (l == 0) + return res; + + if (so_far && (so_far + (l * letter_width) > max_width)) { + res.push(leading); + res = res.concat(splitTextInMultiLine('', 0, line)); + } else if (so_far) { + res.push(leading + ' ' + line); + } else { + if (leading) + res.push(leading); + if (line.length > word_break_index + 1) + res.push(line.slice(0, word_break_index) + '-'); + else + res.push(line); + res = res.concat(splitTextInMultiLine('', 0, line.slice(word_break_index))); + } + + return res; + }; + + for (var i = 0; i < words.length; i++) { + var tmpArr = splitTextInMultiLine( + curr_line, width_so_far, words[i] + ); + + if (curr_line) { + lines = lines.slice(0, lines.length - 2); + } + lines = lines.concat(tmpArr); + curr_line = lines[lines.length - 1]; + width_so_far = (curr_line.length * letter_width); + } + + // Create multiple tspan for each string in array + var t = this.text(x,y,lines).attr(attributes); + t.selectAll("tspan:nth-child(n+2)").attr({ + dy: "1.2em", + x: x + }); + return t; + }; +}); + +if (pgAdmin.Explain) + return pgAdmin.Explain; + +var pgExplain = pgAdmin.Explain = { + // Prefix path where images are stored + prefix: '{{ url_for('misc.static', filename='explain/img') }}/' +}; + +/* + * A map which is used to fetch the image to be drawn and + * text which will appear below it + */ +var imageMapper = { + "Aggregate" : { + "image":"ex_aggregate.png", "image_text":"Aggregate" + }, + 'Append' : { + "image":"ex_append.png","image_text":"Append" + }, + "Bitmap Index Scan" : function(data) { + return { + "image":"ex_bmp_index.png", "image_text":data['Index Name'] + }; + }, + "Bitmap Heap Scan" : function(data) { + return {"image":"ex_bmp_heap.png","image_text":data['Relation Name']}; +}, +"BitmapAnd" : {"image":"ex_bmp_and.png","image_text":"Bitmap AND"}, +"BitmapOr" : {"image":"ex_bmp_or.png","image_text":"Bitmap OR"}, +"CTE Scan" : {"image":"ex_cte_scan.png","image_text":"CTE Scan"}, +"Function Scan" : {"image":"ex_result.png","image_text":"Function Scan"}, +"Foreign Scan" : {"image":"ex_foreign_scan.png","image_text":"Foreign Scan"}, +"Gather" : {"image":"ex_gather_motion.png","image_text":"Gather"}, +"Group" : {"image":"ex_group.png","image_text":"Group"}, +"GroupAggregate": {"image":"ex_aggregate.png","image_text":"Group Aggregate"}, +"Hash" : {"image":"ex_hash.png","image_text":"Hash"}, +"Hash Join": function(data) { + if (!data['Join Type']) return {"image":"ex_join.png","image_text":"Join"}; + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_hash_anti_join.png","image_text":"Hash Anti Join"}; + case 'Semi': return {"image":"ex_hash_semi_join.png","image_text":"Hash Semi Join"}; + default: return {"image":"ex_hash.png","image_text":String("Hash " + data['Join Type'] + " Join" )}; + } +}, +"HashAggregate" : {"image":"ex_aggregate.png","image_text":"Hash Aggregate"}, +"Index Only Scan" : function(data) { + return {"image":"ex_index_only_scan.png","image_text":data['Index Name']}; +}, +"Index Scan" : function(data) { + return {"image":"ex_index_scan.png","image_text":data['Index Name']}; +}, +"Index Scan Backword" : {"image":"ex_index_scan.png","image_text":"Index Backward Scan"}, +"Limit" : {"image":"ex_limit.png","image_text":"Limit"}, +"LockRows" : {"image":"ex_lock_rows.png","image_text":"Lock Rows"}, +"Materialize" : {"image":"ex_materialize.png","image_text":"Materialize"}, +"Merge Append": {"image":"ex_merge_append.png","image_text":"Merge Append"}, +"Merge Join": function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_merge_anti_join.png","image_text":"Merge Anti Join"}; + case 'Semi': return {"image":"ex_merge_semi_join.png","image_text":"Merge Semi Join"}; + default: return {"image":"ex_merge.png","image_text":String("Merge " + data['Join Type'] + " Join" )}; + } +}, +"ModifyTable" : function(data) { + switch (data['Operaton']) { + case "insert": return { "image":"ex_insert.png", + "image_text":"Insert" + }; + case "update": return {"image":"ex_update.png","image_text":"Update"}; + case "Delete": return {"image":"ex_delete.png","image_text":"Delete"}; + } +}, +'Nested Loop' : function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_nested_loop_anti_join.png","image_text":"Nested Loop Anti Join"}; + case 'Semi': return {"image":"ex_nested_loop_semi_join.png","image_text":"Nested Loop Semi Join"}; + default: return {"image":"ex_nested.png","image_text":"Nested Loop " + data['Join Type'] + " Join"}; + } +}, +"Recursive Union" : {"image":"ex_recursive_union.png","image_text":"Recursive Union"}, +"Result" : {"image":"ex_result.png","image_text":"Result"}, +"Sample Scan" : {"image":"ex_scan.png","image_text":"Sample Scan"}, +"Scan" : {"image":"ex_scan.png","image_text":"Scan"}, +"Seek" : {"image":"ex_seek.png","image_text":"Seek"}, +"SetOp" : function(data) { + var strategy = data['Strategy'], + command = data['Command']; + + if(strategy == "Hashed") { + if(command.startsWith("Intersect")) { + if(command == "Intersect All") + return {"image":"ex_hash_setop_intersect_all.png","image_text":"Hashed Intersect All"}; + return {"image":"ex_hash_setop_intersect.png","image_text":"Hashed Intersect"}; + } + else if (command.startsWith("Except")) { + if(command == "Except All") + return {"image":"ex_hash_setop_except_all.png","image_text":"Hashed Except All"}; + return {"image":"ex_hash_setop_except.png","image_text":"Hash Except"}; + } + return {"image":"ex_hash_setop_unknown.png","image_text":"Hashed SetOp Unknown"}; + } + return {"image":"ex_setop.png","image_text":"SetOp"}; +}, +"Seq Scan": function(data) { + return {"image":"ex_scan.png","image_text":data['Relation Name']}; +}, +"Subquery Scan" : {"image":"ex_subplan.png","image_text":"SubQuery Scan"}, +"Sort" : {"image":"ex_sort.png","image_text":"Sort"}, +"Tid Scan" : {"image":"ex_tid_scan.png","image_text":"Tid Scan"}, +"Unique" : {"image":"ex_unique.png","image_text":"Unique"}, +"Values Scan" : {"image":"ex_values_scan.png","image_text":"Values Scan"}, +"WindowAgg" : {"image":"ex_window_aggregate.png","image_text":"Window Aggregate"}, +"WorkTable Scan" : {"image":"ex_worktable_scan.png","image_text":"WorkTable Scan"}, +"Undefined" : {"image":"ex_unknown.png","image_text":"Undefined"}, +} + +// Some predefined constants used to calculate image location and its border +var pWIDTH = pHEIGHT = 100. + IMAGE_WIDTH = IMAGE_HEIGHT = 50; +var offsetX = 200, + offsetY = 60; +var ARROW_WIDTH = 10, + ARROW_HEIGHT = 10; +var TXT_ALLIGN = 5, + TXT_SIZE = "15px"; +var TOTAL_WIDTH = undefined, + TOTAL_HEIGHT = undefined; +var xMargin = 25, + yMargin = 25; +var MIN_ZOOM_FACTOR = 0.01, + MAX_ZOOM_FACTOR = 2, + INIT_ZOOM_FACTOR = 1; + ZOOM_RATIO = 0.05; + + +// Backbone model for each plan property of input JSON object +var PlanModel = Backbone.Model.extend({ + defaults: { + "Plans": [], + level: [], + "image": undefined, + "image_text": undefined, + xpos: undefined, + ypos: undefined, + width: pWIDTH, + height: pHEIGHT + }, + parse: function(data) { + var idx = 1, + lvl = data.level = data.level || [idx], + plans = [], + node_type = data['Node Type'], + // Calculating relative xpos of current node from top node + xpos = data.xpos = data.xpos - pWIDTH, + // Calculating relative ypos of current node from top node + ypos = data.ypos, + maxChildWidth = 0; + + data['width'] = pWIDTH; + data['height'] = pHEIGHT; + + /* + * calculating xpos, ypos, width and height if current node is a subplan + */ + if (data['Parent Relationship'] === "SubPlan") { + data['width'] += (xMargin * 2) + (xMargin / 2); + data['height'] += (yMargin * 2); + data['ypos'] += yMargin; + xpos -= xMargin; + ypos += yMargin; + } + + if(node_type.startsWith("(slice")) + node_type = node_type.substring(0,7); + + // Get the image information for current node + var mapperObj = (_.isFunction(imageMapper[node_type]) && + imageMapper[node_type].apply(undefined, [data])) || + imageMapper[node_type] || 'Undefined'; + + data["image"] = mapperObj["image"]; + data["image_text"] = mapperObj["image_text"]; + + // Start calculating xpos, ypos, width and height for child plans if any + if ('Plans' in data) { + + data['width'] += offsetX; + + _.each(data['Plans'], function(p) { + var level = _.clone(lvl), + plan = new PlanModel(); + + level.push(idx); + plan.set(plan.parse(_.extend( + p, { + "level": level, + xpos: xpos - offsetX, + ypos: ypos + }))); + + if (maxChildWidth < plan.get('width')) { + maxChildWidth = plan.get('width'); + } + + var childHeight = plan.get('height'); + + if (idx !== 1) { + data['height'] = data['height'] + childHeight + offsetY; + } else if (childHeight > data['height']) { + data['height'] = childHeight; + } + ypos += childHeight + offsetY; + + plans.push(plan); + idx++; + }); + } + + // Final Width and Height of current node + data['width'] += maxChildWidth; + data['Plans'] = plans; + + return data; + }, + + /* + * Required to parse and include non-default params of + * plan into backbone model + */ + toJSON: function(non_recursive) { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (non_recursive) { + delete res['Plans']; + } else { + var plans = []; + _.each(res['Plans'], function(p) { + plans.push(p.toJSON()); + }); + res['Plans'] = plans; + } + return res; + }, + + // Draw an arrow to parent node + drawPolyLine: function(g, startX, startY, endX, endY, opts, arrowOpts) { + // Calculate end point of first starting straight line (startx1, starty1) + // Calculate start point of 2nd straight line (endx1, endy1) + var midX1 = startX + ((endX - startX) / 3), + midX2 = startX + (2 * ((endX - startX) / 3)); + + //create arrow head + var arrow = g.polygon( + [0, ARROW_HEIGHT, + (ARROW_WIDTH / 2),ARROW_HEIGHT, + (ARROW_HEIGHT / 4), 0, + 0, ARROW_WIDTH] + ).transform("r90"); + var marker = arrow.marker( + 0, 0, ARROW_WIDTH, ARROW_HEIGHT, 0, (ARROW_WIDTH / 2) + ).attr(arrowOpts); + + // First straight line + g.line( + startX, startY, midX1, startY + ).attr(opts); + + // Diagonal line + g.line( + midX1-1, startY, midX2, endY + ).attr(opts); + + // Last straight line + var line = g.line( + midX2, endY, endX, endY + ).attr(opts); + line.attr({markerEnd: marker}) + }, + + // Draw image, its name and its tooltip + draw: function(s, xpos, ypos, pXpos, pYpos, graphContainer, toolTipContainer) { + var g = s.g(); + var toolTipTable = {}; + var currentXpos = xpos + this.get('xpos') , + currentYpos = ypos + this.get('ypos'), + isSubPlan = (this.get('Parent Relationship') === "SubPlan"); + + // Draw the subplan rectangle + if (isSubPlan) { + g.rect( + currentXpos - this.get('width') + pWIDTH + xMargin, + currentYpos - yMargin, + this.get('width') - xMargin, + this.get('height'), 5 + ).attr({ + stroke: '#444444', + 'strokeWidth': 1.2, + fill: 'gray', + fillOpacity: 0.2 + }); + + //provide subplan name + var text = g.text( + currentXpos + pWIDTH - ( this.get('width') / 2) - xMargin, + currentYpos + pHEIGHT - (this.get('height') / 2) - yMargin, + this.get('Subplan Name') + ).attr({ + fontSize: TXT_SIZE, "text-anchor":"start", + fill: 'red' + }); + } + + // Draw the actual image for current node + var image = g.image( + pgExplain.prefix + this.get('image'), + currentXpos + (pWIDTH - IMAGE_WIDTH) / 2, + currentYpos + (pHEIGHT - IMAGE_HEIGHT) / 2, + IMAGE_WIDTH, + IMAGE_HEIGHT + ); + + // Draw tooltip + var image_data = this.toJSON(); + image.mouseover(function(evt){ + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + var tooltip = $('<table></table>', + { + class: "pgadmin-tooltip-table", + style: "border-collapse: collapse; border-spacing: 1px; top: auto; left: auto;" + } + ).appendTo(toolTipContainer); + _.each(image_data, function(value,key) { + if(key !== 'image' && key !== 'Plans' && + key !== 'level' && key !== 'image' && + key !== 'image_text' && key !== 'xpos' && + key !== 'ypos' && key !== 'width' && + key !== 'height') { + tooltip.append( '<tr><td class="label explain-tooltip">' + key + '</td><td class="label explain-tooltip-val">' + value + '</td></tr>' ); + }; + }); + + var zoomFactor = graphContainer.data('zoom-factor'); + + // Calculate co-ordinates for tooltip + var toolTipX = ((currentXpos + pWIDTH) * zoomFactor - graphContainer.scrollLeft()); + var toolTipY = ((currentYpos + pHEIGHT) * zoomFactor - graphContainer.scrollTop()); + + // Recalculate x.y if tooltip is going out of screen + if(graphContainer.width() < (toolTipX + toolTipContainer[0].clientWidth)) + toolTipX -= (toolTipContainer[0].clientWidth + (pWIDTH*zoomFactor)); + //if(document.children[0].clientHeight < (toolTipY + toolTipContainer[0].clientHeight)) + if(graphContainer.height() < (toolTipY + toolTipContainer[0].clientHeight)) + toolTipY -= (toolTipContainer[0].clientHeight + ((pHEIGHT/2)*zoomFactor)); + + toolTipX = toolTipX < 0 ? 0 : (toolTipX); + toolTipY = toolTipY < 0 ? 0 : (toolTipY); + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({'opacity': '0.8'}); + toolTipContainer.css('left', toolTipX); + toolTipContainer.css( 'top', toolTipY); + }); + + // Remove tooltip when mouse is out from node's area + image.mouseout(function() { + toolTipContainer.empty(); + toolTipContainer.css({'opacity': '0'}); + toolTipContainer.css('left', 0); + toolTipContainer.css( 'top', 0); + }); + + // Draw text below the node + var label = g.g(); + g.multitext( + currentXpos + (pWIDTH / 2), + currentYpos + pHEIGHT - TXT_ALLIGN, + this.get('image_text'), + 150, + {"font-size": TXT_SIZE ,"text-anchor":"middle"} + ); + + // Draw Arrow to parent only its not the first node + if (!_.isUndefined(pYpos)) { + var startx = currentXpos + pWIDTH; + var starty = currentYpos + (pHEIGHT / 2); + var endx = pXpos - ARROW_WIDTH; + var endy = pYpos + (pHEIGHT / 2); + var start_cost = this.get("Startup Cost"), + total_cost = this.get("Total Cost"); + + // Calculate arrow width according to cost of a particular plan + var arrow_size = Math.round(Math.log((start_cost+total_cost)/2 + start_cost)); + arrow_size = arrow_size < 1 ? 1 : arrow_size > 10 ? 10 : arrow_size; + + var arrow_view_box = [0, 0, 2*ARROW_WIDTH, 2*ARROW_HEIGHT]; + var opts = {stroke: "#000000", strokeWidth: arrow_size + 1}, + subplanOpts = {stroke: "#866486", strokeWidth: arrow_size + 1}, + arrowOpts = {viewBox: arrow_view_box.join(" ")}; + + // Draw an arrow from current node to its parent + this.drawPolyLine( + g, startx, starty, endx, endy, + isSubPlan ? subplanOpts : opts, arrowOpts + ); + } + + var plans = this.get('Plans'); + + // Draw nodes for current plan's children + _.each(plans, function(p) { + p.draw(s, xpos, ypos, currentXpos, currentYpos, graphContainer, toolTipContainer); + }); + } +}); + +// Main backbone model to store JSON object +var MainPlanModel = Backbone.Model.extend({ + defaults: { + "Plan": undefined, + xpos: 0, + ypos: 0, + }, + initialize: function() { + this.set("Plan", new PlanModel()); + }, + + // Parse the JSON data and fetch its children plans + parse: function(data) { + if (data && 'Plan' in data) { + var plan = this.get("Plan"); + plan.set( + plan.parse( + _.extend( + data['Plan'], { + xpos: 0, + ypos: 0 + }))); + + data['xpos'] = 0; + data['ypos'] = 0; + data['width'] = plan.get('width') + (xMargin * 2); + data['height'] = plan.get('height') + (yMargin * 2); + + delete data['Plan']; + } + + return data; + }, + toJSON: function() { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (res.Plan) { + res.Plan = res.Plan.toJSON(); + } + + return res; + }, + draw: function(s, xpos, ypos, graphContainer, toolTipContainer) { + var g = s.g(); + + //draw the border + g.rect( + 0, 0, this.get('width') - 10, this.get('height') - 10, 5 + ).attr({ + stroke: '#FFEBCD', 'strokeWidth': 1.2, + fill: '#FFF8DC', fillOpacity: 0.5 + }); + + //Fetch total width, height + TOTAL_WIDTH = this.get('width'); + TOTAL_HEIGHT = this.get('height'); + var plan = this.get('Plan'); + + //Draw explain graph + plan.draw(g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer); + } +}); + +// Parse and draw full graphical explain +_.extend( + pgExplain, { + // Assumption container is a jQuery object + DrawJSONPlan: function(container, plan) { + var my_plans = []; + container.empty(); + var curr_zoom_factor = 1.0; + + var zoomArea =$('<div></div>', { + class: 'pg-explain-zoom-area btn-group', + role: 'group' + }).appendTo(container), + zoomInBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom in' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-search-plus' + })), + zoomToNormal = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom to original' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-arrows-alt' + })) + zoomOutBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom out' + }).appendTo(zoomArea).append( + $('<i></i>', { + class: 'fa fa-search-minus' + })); + + // Main div to be drawn all images on + var planDiv = $('<div></div>', + {class: "pgadmin-explain-container"} + ).appendTo(container), + // Div to draw tool-tip on + toolTip = $('<div></div>', + {id: "toolTip", + class: "pgadmin-explain-tooltip" + } + ).appendTo(container); + toolTip.empty(); + planDiv.data('zoom-factor', curr_zoom_factor); + + var w = 0, h = 0, + x = xMargin, h = yMargin; + + _.each(plan, function(p) { + var main_plan = new MainPlanModel(); + + // Parse JSON data to backbone model + main_plan.set(main_plan.parse(p)); + w = main_plan.get('width'); + h = main_plan.get('height'); + + var s = Snap(w, h), + $svg = $(s.node).detach(); + planDiv.append($svg); + + main_plan.draw(s, w - xMargin, yMargin, planDiv, toolTip); + + var initPanelWidth = planDiv.width(), + initPanelHeight = planDiv.height(); + + /* + * Scale graph in case its width is bigger than panel width + * in which the graph is displayed + */ + if(initPanelWidth < w) { + var width_ratio = initPanelWidth / w; + + curr_zoom_factor = width_ratio; + curr_zoom_factor = curr_zoom_factor < MIN_ZOOM_FACTOR ? MIN_ZOOM_FACTOR : curr_zoom_factor; + curr_zoom_factor = curr_zoom_factor > INIT_ZOOM_FACTOR ? INIT_ZOOM_FACTOR : curr_zoom_factor; + + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + } + + zoomInBtn.on('click', function(e){ + curr_zoom_factor = ((curr_zoom_factor + ZOOM_RATIO) > MAX_ZOOM_FACTOR) ? MAX_ZOOM_FACTOR : (curr_zoom_factor + ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomInBtn.blur(); + }); + + zoomOutBtn.on('click', function(e) { + curr_zoom_factor = ((curr_zoom_factor - ZOOM_RATIO) < MIN_ZOOM_FACTOR) ? MIN_ZOOM_FACTOR : (curr_zoom_factor - ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomOutBtn.blur(); + }); + + zoomToNormal.on('click', function(e) { + curr_zoom_factor = INIT_ZOOM_FACTOR; + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomToNormal.blur(); + }); + }); + } + }); + + return pgExplain; +}); diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index 45612f6..cc74b29 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -247,3 +247,9 @@ background: #5B9CEF; color: white; } + +.sql-editor-explain { + height: 100%; + width: 100%; + overflow: auto; +} diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index d617d7a..9c065e2 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -1,9 +1,9 @@ define( - ['jquery', 'underscore', 'alertify', 'pgadmin', 'backbone', 'backgrid', 'codemirror', + ['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin', 'backbone', 'backgrid', 'codemirror', 'pgadmin.misc.explain', 'codemirror/mode/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line', 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter', 'bootstrap', 'pgadmin.browser', 'wcdocker'], - function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) { + function($, _, S, alertify, pgAdmin, Backbone, Backgrid, CodeMirror, pgExplain) { // Some scripts do export their object in the window only. // Generally the one, which do no have AMD support. @@ -159,6 +159,12 @@ define( "click #btn-auto-commit": "on_auto_commit", "click #btn-auto-rollback": "on_auto_rollback", "click #btn-clear-history": "on_clear_history", + "click #btn-explain": "on_explain", + "click #btn-explain-analyze": "on_explain_analyze", + "click #btn-explain-verbose": "on_explain_verbose", + "click #btn-explain-costs": "on_explain_costs", + "click #btn-explain-buffers": "on_explain_buffers", + "click #btn-explain-timing": "on_explain_timing", "change .limit": "on_limit_change" }, @@ -217,10 +223,53 @@ define( '</button>', '<ul class="dropdown-menu dropdown-menu">', '<li>', + '<a id="btn-explain" href="#">', + '<span>{{ _('Explain') }}</span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-analyze" href="#">', + '<span>{{ _('Explain analyze') }}</span>', + '</a>', + '</li>', + '<li class="divider"></li>', + '<li class="dropdown-submenu dropdown-submenu">', + '<a href="#">{{ _('Explain Options') }}</a>', + '<ul class="dropdown-menu">', + '<li>', + '<a id="btn-explain-verbose" href="#" tabindex="-1">', + '<i class="explain-verbose fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Verbose') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-costs" href="#">', + '<i class="explain-costs fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Costs') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-buffers" href="#">', + '<i class="explain-buffers fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Buffers') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-timing" href="#">', + '<i class="explain-timing fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Timing') }} </span>', + '</a>', + '</li>', + '</ul>', + '</li>', + '<li class="divider"></li>', + '<li>', '<a id="btn-auto-commit" href="#">', '<i class="auto-commit fa fa-check" aria-hidden="true"></i>', '<span> {{ _('Auto-Commit') }} </span>', '</a>', + '</li>', + '<li>', '<a id="btn-auto-rollback" href="#">', '<i class="auto-rollback fa fa-check visibility-hidden" aria-hidden="true"></i>', '<span> {{ _('Auto-Rollback') }} </span>', @@ -377,7 +426,7 @@ define( height:'100%', isCloseable: false, isPrivate: true, - content: '<div class="sql-editor-explian"></div>' + content: '<div class="sql-editor-explain"></div>' }) var messages = new pgAdmin.Browser.Panel({ @@ -768,6 +817,78 @@ define( self, self.handler ); + }, + + // Callback function for explain button click. + on_explain: function() { + var self = this; + + // Trigger the explain signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain', + self, + self.handler + ); + }, + + // Callback function for explain analyze button click. + on_explain_analyze: function() { + var self = this; + + // Trigger the explain analyze signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-analyze', + self, + self.handler + ); + }, + + // Callback function for explain option "verbose" button click + on_explain_verbose: function() { + var self = this; + + // Trigger the explain "verbose" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-verbose', + self, + self.handler + ); + }, + + // Callback function for explain option "costs" button click + on_explain_costs: function() { + var self = this; + + // Trigger the explain "costs" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-costs', + self, + self.handler + ); + }, + + // Callback function for explain option "buffers" button click + on_explain_buffers: function() { + var self = this; + + // Trigger the explain "buffers" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-buffers', + self, + self.handler + ); + }, + + // Callback function for explain option "timing" button click + on_explain_timing: function() { + var self = this; + + // Trigger the explain "timing" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-timing', + self, + self.handler + ); } }); @@ -830,6 +951,12 @@ define( self.on('pgadmin-sqleditor:button:download', self._download, self); self.on('pgadmin-sqleditor:button:auto_rollback', self._auto_rollback, self); self.on('pgadmin-sqleditor:button:auto_commit', self._auto_commit, self); + self.on('pgadmin-sqleditor:button:explain', self._explain, self); + self.on('pgadmin-sqleditor:button:explain-analyze', self._explain_analyze, self); + self.on('pgadmin-sqleditor:button:explain-verbose', self._explain_verbose, self); + self.on('pgadmin-sqleditor:button:explain-costs', self._explain_costs, self); + self.on('pgadmin-sqleditor:button:explain-buffers', self._explain_buffers, self); + self.on('pgadmin-sqleditor:button:explain-timing', self._explain_timing, self); if (self.is_query_tool) { self.gridView.query_tool_obj.refresh(); @@ -1083,10 +1210,24 @@ define( var message = 'Total query runtime: ' + self.total_time + '\n' + self.rows_affected + ' rows retrieved.'; $('.sql-editor-message').text(message); - // Add the data to the collection and render the grid. - self.collection.add(data.result, {parse: true}); - self.gridView.render_grid(self.collection, self.columns); - self.gridView.data_output_panel.focus(); + /* Add the data to the collection and render the grid. + * In case of Explain draw the graph on explain panel + * and add json formatted data to collection and render. + */ + var explain_data_array = []; + if('QUERY PLAN' in data.result[0]) { + self.gridView.explain_panel.focus(); + var explain_data = {'QUERY PLAN' : JSON.stringify(data.result[0]['QUERY PLAN'], null, 2)}; + explain_data_array.push(explain_data); + pgExplain.DrawJSONPlan($('.sql-editor-explain'), data.result[0]['QUERY PLAN']); + self.collection.add(explain_data_array, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + } + else { + self.collection.add(data.result, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + self.gridView.data_output_panel.focus(); + } // Hide the loading icon self.trigger('pgadmin-sqleditor:loading-icon:hide'); @@ -1812,7 +1953,7 @@ define( // This function will fetch the sql query from the text box // and execute the query. - _execute: function () { + _execute: function (explain_prefix) { var self = this, sql = '', history_msg = ''; @@ -1831,6 +1972,9 @@ define( else sql = self.gridView.query_tool_obj.getValue(); + if (explain_prefix != undefined) + sql = explain_prefix + ' ' + sql; + self.query_start_time = new Date(); self.query = sql; self.rows_affected = 0; @@ -2149,6 +2293,71 @@ define( alertify.alert('Auto Commit Error', msg); } }); + }, + + // This function will + _explain: function() { + var self = this; + var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'off' : 'on'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'off' : 'on'; + var buffers = $('.explain-buffers').hasClass('visibility-hidden') ? 'off' : 'on'; + var timing = $('.explain-timing').hasClass('visibility-hidden') ? 'off' : 'on'; + + var explain_query = 'Explain (format json, ANALYZE off, VERBOSE %s, COSTS %s, BUFFERS %s, TIMING %s) '; + explain_query = S(explain_query).sprintf(verbose, costs, buffers, timing).value(); + self._execute(explain_query); + }, + + // This function will + _explain_analyze: function() { + var self = this;var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'off' : 'on'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'off' : 'on'; + var buffers = $('.explain-buffers').hasClass('visibility-hidden') ? 'off' : 'on'; + var timing = $('.explain-timing').hasClass('visibility-hidden') ? 'off' : 'on'; + + var explain_query = 'Explain (format json, ANALYZE on, VERBOSE %s, COSTS %s, BUFFERS %s, TIMING %s) '; + explain_query = S(explain_query).sprintf(verbose, costs, buffers, timing).value(); + self._execute(explain_query); + }, + + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + var self = this; + if ($('.explain-verbose').hasClass('visibility-hidden') === true) + $('.explain-verbose').removeClass('visibility-hidden'); + else { + $('.explain-verbose').addClass('visibility-hidden'); + } + }, + + // This function will toggle "costs" option in explain + _explain_costs: function() { + var self = this; + if ($('.explain-costs').hasClass('visibility-hidden') === true) + $('.explain-costs').removeClass('visibility-hidden'); + else { + $('.explain-costs').addClass('visibility-hidden'); + } + }, + + // This function will toggle "buffers" option in explain + _explain_buffers: function() { + var self = this; + if ($('.explain-buffers').hasClass('visibility-hidden') === true) + $('.explain-buffers').removeClass('visibility-hidden'); + else { + $('.explain-buffers').addClass('visibility-hidden'); + } + }, + + // This function will toggle "timing" option in explain + _explain_timing: function() { + var self = this; + if ($('.explain-timing').hasClass('visibility-hidden') === true) + $('.explain-timing').removeClass('visibility-hidden'); + else { + $('.explain-timing').addClass('visibility-hidden'); + } } } ); ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-04-25 09:36 Sanket Mehta <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-04-25 09:36 UTC (permalink / raw) To: pgadmin-hackers Hi, This patch includes the patch sent earlier for stand alone graphical explain. And also "horizontal lines are not proper" bug is fixed in the same which was reported by Dave in previous patch. Regards, Sanket Mehta Sr Software engineer Enterprisedb On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta <[email protected] > wrote: > Hi Team, > > PFA the first patch for graphical explain integrated in sql editor. > > Below are the few things which are different from previous patch which was > sent for stand alone graphical explain. > > - Now user can select Explain/Explain Analyze with four optional > properties (Verbose, costs, timing and buffers) > > - Initially graph will be scale (according to only its width not height) > to fit to screen so no blank space will be there in case of very large > graph. > > - Along with zoom in/out button, "zoom to original" button is also > provided, by clicking on which graph will be scale to its original size > (not same as initial one which is according to screen size). > > Please do review this patch and let me know in case you have any comments. > > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-04-25 11:06 Ashesh Vashi <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Ashesh Vashi @ 2016-04-25 11:06 UTC (permalink / raw) To: Sanket Mehta <[email protected]>; +Cc: pgadmin-hackers Hi Sanket, Please find the review comments. - Please add the missing 'explain.css'. - The application should be smart enough to handle conflict in options. i.e. Buffer is not a valid options without EXPLAIN ANALYZE. - A statement having EXPLAIN keywords with different format should at least render the output in the data-grid. i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; - Please use the keywords used in the EXPLAIN statement in capital. - Explain should not work with empty string. - Font size in the tooltip is very small. - Smoothing the zoom functionality. - Arrow marker is hardly visible. -- Thanks & Regards, Ashesh Vashi EnterpriseDB INDIA: Enterprise PostgreSQL Company <http://www.enterprisedb.com; *http://www.linkedin.com/in/asheshvashi* <http://www.linkedin.com/in/asheshvashi; On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta <[email protected] > wrote: > Hi, > > This patch includes the patch sent earlier for stand alone graphical > explain. > > And also "horizontal lines are not proper" bug is fixed in the same which > was reported by Dave in previous patch. > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > > On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < > [email protected]> wrote: > >> Hi Team, >> >> PFA the first patch for graphical explain integrated in sql editor. >> >> Below are the few things which are different from previous patch which >> was sent for stand alone graphical explain. >> >> - Now user can select Explain/Explain Analyze with four optional >> properties (Verbose, costs, timing and buffers) >> >> - Initially graph will be scale (according to only its width not height) >> to fit to screen so no blank space will be there in case of very large >> graph. >> >> - Along with zoom in/out button, "zoom to original" button is also >> provided, by clicking on which graph will be scale to its original size >> (not same as initial one which is according to screen size). >> >> Please do review this patch and let me know in case you have any comments. >> >> >> Regards, >> Sanket Mehta >> Sr Software engineer >> Enterprisedb >> > > ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-09 15:19 Sanket Mehta <[email protected]> parent: Ashesh Vashi <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-05-09 15:19 UTC (permalink / raw) To: Ashesh Vashi <[email protected]>; +Cc: pgadmin-hackers Hi, PFA revised patch according to Ashesh's comments. Please find my response inline. I am currently adding minimap feature in graphical explain. I will send a new patch for the same. Regards, Sanket Mehta Sr Software engineer Enterprisedb On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi <[email protected] > wrote: > Hi Sanket, > > Please find the review comments. > - Please add the missing 'explain.css'. > Done > - The application should be smart enough to handle conflict in options. > i.e. > Buffer is not a valid options without EXPLAIN ANALYZE. > Done > - A statement having EXPLAIN keywords with different format should at > least render the output in the data-grid. > i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; > Done > - Please use the keywords used in the EXPLAIN statement in capital. > Done > - Explain should not work with empty string. > Done > - Font size in the tooltip is very small. > Done > > - Smoothing the zoom functionality. > Minimap will be added and zoom functionality will be removed. So it is ignored. - Arrow marker is hardly visible. > Done. > > > -- > > Thanks & Regards, > > Ashesh Vashi > EnterpriseDB INDIA: Enterprise PostgreSQL Company > <http://www.enterprisedb.com; > > > *http://www.linkedin.com/in/asheshvashi* > <http://www.linkedin.com/in/asheshvashi; > > On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < > [email protected]> wrote: > >> Hi, >> >> This patch includes the patch sent earlier for stand alone graphical >> explain. >> >> And also "horizontal lines are not proper" bug is fixed in the same which >> was reported by Dave in previous patch. >> >> Regards, >> Sanket Mehta >> Sr Software engineer >> Enterprisedb >> >> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >> [email protected]> wrote: >> >>> Hi Team, >>> >>> PFA the first patch for graphical explain integrated in sql editor. >>> >>> Below are the few things which are different from previous patch which >>> was sent for stand alone graphical explain. >>> >>> - Now user can select Explain/Explain Analyze with four optional >>> properties (Verbose, costs, timing and buffers) >>> >>> - Initially graph will be scale (according to only its width not >>> height) to fit to screen so no blank space will be there in case of very >>> large graph. >>> >>> - Along with zoom in/out button, "zoom to original" button is also >>> provided, by clicking on which graph will be scale to its original size >>> (not same as initial one which is according to screen size). >>> >>> Please do review this patch and let me know in case you have any >>> comments. >>> >>> >>> Regards, >>> Sanket Mehta >>> Sr Software engineer >>> Enterprisedb >>> >> >> > -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] integrated_graphical_explainV4.patch (484.3K, 3-integrated_graphical_explainV4.patch) download | inline diff: diff --git a/libraries.txt b/libraries.txt index 9fcf755..ad1c004 100644 --- a/libraries.txt +++ b/libraries.txt @@ -27,3 +27,4 @@ backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all +Snap.svg 0.4.1 APACHE http://snapsvg.io/ diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index f461cbe..33c693e 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -6,28 +6,59 @@ # This software is released under the PostgreSQL Licence # ########################################################################## - """A blueprint module providing utility functions for the application.""" -import datetime -from flask import session, current_app +from flask import url_for, render_template from pgadmin.utils import PgAdminModule import pgadmin.utils.driver as driver +import config MODULE_NAME = 'misc' -# Initialise the module -blueprint = PgAdminModule(MODULE_NAME, __name__, - url_prefix='') +class MiscModule(PgAdminModule): -########################################################################## -# A special URL used to "ping" the server -########################################################################## + def get_own_javascripts(self): + scripts = [{ + 'name': 'pgadmin.misc.explain', + 'path': url_for('misc.index') + 'explain/explain', + 'preloaded': False + },{ + 'name': 'snap.svg', + 'path': url_for( + 'misc.static', filename='explain/js/' + ( + 'snap.svg' if config.DEBUG else 'snap.svg-min' + )), + 'preloaded': False + }] + return scripts + + def get_own_stylesheets(self): + stylesheets = [] + stylesheets.append(url_for('misc.static', filename='explain/css/explain.css')) + return stylesheets + # Initialise the module +blueprint = MiscModule(MODULE_NAME, __name__, static_url_path="/static") + + ########################################################################## + # A special URL used to "ping" the server + ########################################################################## + [email protected]("/") +def index(): + return '' @blueprint.route("/ping", methods=('get', 'post')) def ping(): - """Generate a "PING" response to indicate that the server is alive.""" - driver.ping() + driver.ping() + +def demo(): + return render_template('demo_explain.html') + [email protected]("/explain/explain.js") +def explain_js(): + return render_template("explain/js/explain.js") - return "PING" [email protected]("/sample") +def sample(): + return render_template('sample.html') diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css new file mode 100644 index 0000000..49a4bc4 --- /dev/null +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -0,0 +1,56 @@ +.pg-explain-zoom-area { + position: absolute; + top: 5px; + left: 5px; + opacity: 0.5; + cursor: pointer; +} + +.pg-explain-zoom-btn { + top: 5px; + min-width: 25px; + cursor: pointer; + border: 1px solid transparent; +} + +.pg-explain-zoom-area:hover { + opacity: 1; +} + +.explain-tooltip { + display: table-cell; + text-align: left; + white-space: nowrap; + line-height: 10px !important; + padding: 2px !important; + font-size: small; +} + +td.explain-tooltip-val { + display: table-cell; + text-align: left; + white-space: pre-wrap; + font-size: smaller; +} + +.pgadmin-explain-tooltip { + position: absolute; + padding:5px; + border: 1px solid white; + opacity:0; + color: cornsilk; + background-color: #010125; +} + +.pgadmin-tooltip-table { + border-collapse: collapse; + border-spacing: 1px; + top: auto; + left: auto; +} + +.pgadmin-explain-container { + height: 100%; + width: 100%; + overflow: auto; +} \ No newline at end of file diff --git a/web/pgadmin/misc/static/explain/img/ex_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe75d909f5092c4d3ba8978c75fbc57d7f606d GIT binary patch literal 574 zcmV-E0>S->P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10lP^=K~!jg?U_w#!!Qs=pNrR76nc`JAiEyfyPUu$F?5lg!9`tE zrVdorjI6O#*B=N1Q4~GTk7uODImZ$7QhEcqbb{2T!+^AsNlnvqz}0v!OZCpVcg+u) zSl03oH-ylcGy!)Fj09u=UN>$mMIX+&H|b<ajP!gzp{f<N2t38e1(}OYz(X)^Z9SDm zaL$Pb&;cXx85twc3D+9}YYwWtX(n61tgLAZVhA&A0ZDox`m}f_o&;Lp=3^|TZAm4? zB8D-uw2Hk&77xL~GD+H8Yh{L+-D~onRU64N$mC{z9Z`Z<4$%uyDn(tUuBBqiTE>@* zne6>YDVVIT^|Y|u&2%+YKxQ4H!ZKN8+Uk0kwJKPjW&<(>@$PjAe4RCOnSn%Nr0(=P zYi|fJ04V_hnL$cH0K3&%;sz_V=BgQD)cm$)2vvhs6@*_isdrBfc8kD{yg=7gktITF z+PGFu2!0OeLWgu>5LFp3D9xourL!bQu%a?wd{rRqFIvi++{=Q!&>aaV%KTa{dS;2c z$5o3IhEOTyT37x61pK30-JX4KbAS7Pk<5;R_SRus>jbGyCrEAj0!#X?PWurOy8r+H M07*qoM6N<$f>VU-$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_append.png b/web/pgadmin/misc/static/explain/img/ex_append.png new file mode 100644 index 0000000000000000000000000000000000000000..017a2068b735f13cb89a3bcb2832e5880d17df56 GIT binary patch literal 1162 zcmV;51a<p~P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(LcQrnzUg(&?|IPgRl@0p)bM7=>}tvEZ_4YI+3|bM?Sj$mrrz?7)b5hj z@2}zW1*hRn!RZ^W<6Fh+V#n(^x8+d2=WEC4a+aaNk2du1$nfm9@9MSh>9q3g#qH&> z?c}iR<FN7S!|>?B>));G-mL1~tMBB$>*k;D>$d6On&{t|?&h=S+m`0ol<eWI<I<1f z(2eQZsp{jL=-rs*){^1Oi|N^?<kgYn(~#oMjOf><@94Ab;k?JHb@1lE=hUR;)1&O& zx!}r)-o=I9!-U<zg67eo-^hpM&!OhgqTIiL<j$Y(=D_CCqwCqW<jtPr%%0=Rp4+{D z+PZy)sbo@(8Kui)sL*Ju)oiZXakAicwdHz}mC<Hv(aX&7yuR$dzwOS>^3l=q!NTst z#P8G8^VQY#$jI=?$??j|@!8t--ro1u*Y)Ay_q@IAr>W+ss^`DI?yaxsud(UH#qY<+ z@3pq;x47%Lx$M-`^vB2WiI(>{00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0zpYcK~zY`?U3tJ5>Xh&?SzGeqJ$LLD=fGO%SB*ek((>YO)i2W3vOk#CSYi4 znRfSIZ+9mfuyZIJXZldjhj-?kd4K0Q&oeUeU#e~(MZ}3i&`phI^cK3U)oRDk*qyt& zaWp=m*H5C!DTCo2!Xg@@(Kw2xO(xTQ^uTO3>(InQtyYhwW@dB-G{|N8&s`p=e<n^G z0<#v2W%goPDar;m`yB0nd8dnU0~WD(JRXZWy+HYV3x2Q%f<YFXp-`9`j6@<<8Ch7g z109S;oxp^{vG^dw8;L|H@Gk}eG_cV`k^ych7US{Aj}#QOtfZjT6pWn09q0KJ7I_Sc zh!gMP^;&1a=J(qj;9yzj3b;8go`O_5oyp=qCa3T%U!+JRLvo5(EXPASzgj5bk-lP+ zO0n@=u9Sw%YN1djA(xBgOQn1U)(VwM6_42b_BpvF*6CW8Q^eI2nT;%D%hhV_+8T4v zEISV?48yr0#q(+T{k3Ab2DQz)fOi2p8cn$56iaG~e0~Fpl}e)u^=7jv;1M>FxKwPp z(r9dgKt_How%TaO#{-achU4Ux__UIuSXNThl@v8W5U#DUt7}W#B5ow&NzYaPMkJm- z`+3#B5v1H~KNqnZ(M8-Adt7=qvQOWu;_p1vqZcA^BYthzl84euNfB}45NYSt?ruwJ zclP#POWpm0H;2+;tKB}5j=J6Bw-Oe4cXIOnRO+0aefTJS`uyeVj?_BsblTFl^ZkS4 zzljW=<qD1clll(R-{b2g;$(6F001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@z zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUh cIxsdXFf}?bFv^!ztN;K207*qoM6N<$g1#AbUjP6A literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_and.png b/web/pgadmin/misc/static/explain/img/ex_bmp_and.png new file mode 100644 index 0000000000000000000000000000000000000000..64d5869dcfcf9d94d031fa068cff93ea929180b2 GIT binary patch literal 1006 zcmV<K0}=d*P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004)P)t-smD2kF z003rd(R6flb#--ic6N7ncY1nyHi*G{dwYC*e13j@fPjF4f`WsCgM@^HhlhuVh=_}e zi;azqj*gCGmC%omkC2d%k&%&&j=z$UlEIHQm6er`lHGcqshOFXoSdAVo}QbW#Gjv^ zrlzK+r>D86a;T`NPQK>5s&lKWtGldpyRCMut*u(Y=dP}<ys&q#udltad8@4GzOs6W zx!ba`vSh{Rx3{;mwCZuo?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?Zd;v-NJ*w!S2S! z#*5VM-^PaD$cK{E@5aaP;L3^0%F2}3@Z-y#<IJAq&7R`WjpWXs%+2x5&hq8Zq2|$| z)6>(Y-ty(vljhW<)z#JK)upZ9^VHPy=+~y`*Qe^(w&~ia>DsB<+S=*ds_NXT>)W{8 z+}z#W-Rs`0?A^KE-rnrst?b~g?cclJ-uCR`ui@e0?BlTF;^Ob*zvboS@aDkq=fUUa z=jrL`@$1Cu>gw?D@bU5S^78WY^Yiuf_4fAm`1ttw`T70*{r~^}C9&%N00001bW%=J z06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0q;pfK~zY`?UY$l6G0S(b8}-Di3kcP z+Oo)^h$4bwltoqvL?DD{Mjf_nBqD~O2?A~ymixDzo*9a*Gm})MC?7Zv{c`K8Gv{>Q zvDq$ko~o9(s?QF(wL!N4k*52GJqwax@WJEtiUu~Rr}eShD?&VOcaK*pj!Vugb=sg# zfY{%@e)DeKes;iqrqk&yCPD_D!r-C^Nk4<GWMRlx_z0E==`xVDE_fnFj<OJC>PwuJ zQ#!=9lF84TBBa*NRjVOi9LP1IA^nW2-@@fKw*1L<;8opaGaip`h_l>+MlB1G6SG9S z=+u$;BX}4UBk&Ro<O=>E`h+(O1ZE*><<f@Dv{HsEI<ou#?nSH``|ZN(SURV-%r>Ht zNXoo1qP+&hYdgl><kJ{stMHBkrzooyKsJ^Ng_cqlS=#YAjp3zO3@bPinuH0(v@xPG z-th~(T!n2MS(<=x#ngpg%P%#>ef9pot6A9mcrN5H3(-xi$?R{pAeQfQB&8_Is%c|H zG5v{QDc(Jx{2HTgO)iJ4;r-tV>{PR?%CelW*cUn`^~2;*7z$c$rLkbz!Q>%$6)bF# zgDMhW1^r<X!9XBkv6Uy4*H)f(3HbeC^EY-H@%KXSjQLiI5MN;~GdYo*S;9V_FI=R? cF7zMiA0?@qIju>9W&i*H07*qoM6N<$f<qfLO8@`> literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png new file mode 100644 index 0000000000000000000000000000000000000000..2657d8c39328bfc80751c60db9d3ab4341c0de35 GIT binary patch literal 1106 zcmV-Y1g-mtP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s00000 z003rd(Nc{WHi*Gol_FY@Wn`8)38~@|tKwvp&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPGu5^~NHbTAWN5AP#zUE86=}y7vTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q^_*?AyJGyuIvu(eH!N?S#?pz`^c> z)9|d;ZHv_Ik=5>!)$gv_amL5*l-Tf>+3~XAcCFUw%+2wj+wtexE9lxP&Cc@b+bZna zD(>4V@7yZ!+$!?iD)ihcx!dfw=Y00vDy`r1`Q0h{-6_=6^RD3Y``#)1-YNdxDZbwA zx$A$x-|oWT?z`@S?c-qY<6p($@9^Ybyzqqb<X`jTU&rI{$m8(y<zMvWU&`a~_2pmp z<zM*aU(4k2-rn~3=3n~eU(Mz6{N`W&=3mk0^3&+^^6H1w>GRa-^z`e8*6H;2>xcO3 zhu7-$`s|1O?1ujAhT-q`mEcQQ00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94 zoEQKA0&7V`K~zY`?Ud_N(?Ar(NfQ+@uBZsUQR*A(3k7^uiA_xlwb7<XX$T2Wl46zw z3Z<omf1TZggd}Y;GR`=D;C$H3?B=&;&b@cGr{_ffM12%iU&sC(Yu~pzN7RRBuO_}z z9SHSg=<4;C)SHp}k3Ldg#wI3zy8lp*uid=+whJ=U+k5r~HGFAc;3+jWJaTW6`U{t^ zEElbP-|8I2KEHnd^>^&(-vmu3&<E7Y<#G+wL{Y4Rx+F<;;36;16PJH@5PE-~#z=W; ziYWt;VNw#1SeBJN2=S2cA-lUa!Z3^o#8j#a5_H+w@gP!)Wi2G_L4sKv#G9fn%W}g- z`eRt9$y)*BIl%I*K9?(GoOF@xZQI4ZUy^0CDl3(yC(CW(0vV5!j_A!z8h-}~mT*$6 za2%)l5JX@-7#$sd_le%vpcj!ymO#PfbULko3dd#C2p5DnE;2^GRe;K6G8zcaf)Jd= zPSH>*C`D7%v}T}UXUKCdvcCQ&74!AQMsP2b2D)EWk&C8PTM^wqM7$}qY%Zrq%-GtR zg(zuUST%!@YA%<95iYB%7Gn28&1ADxp!<=IEX&Il;!V+l5Vj&_Y-#D(Gq$jB=z@FE z)OFo<X@_?I6h_E^1__=pLT79oBQrC<=I0lWMDj$zh?ucbsf$a&>(Y@0AyyV$hfa#N zVHoX*8Jn9s_Kewxb3cRzb}`Mpu<oOWZ+aR(egNk4c?ck1K*3ExD4Jn2MsLj~le1g2 zh42s<1wlYavFJkrE~R9$WV`UZ0SrM9%pelTlE5>D9%WyOJ=2@Tu2_G^GagZ~6a9ZW Y0Mz-{B6#`Cr~m)}07*qoM6N<$f){{JGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_index.png b/web/pgadmin/misc/static/explain/img/ex_bmp_index.png new file mode 100644 index 0000000000000000000000000000000000000000..23b9733b56792533e4db25ca9890a0a0140c6ff9 GIT binary patch literal 1172 zcmV;F1Z(?=P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004@P)t-s000{R z003rd(Nc{WHi*Gol_FY@Wn`8)45{LDla^$a&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPPu{MmZbjzYxL%irozv)iC=1#%sTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q|V#etORA+r5d~zJR>F?0eDg-NAx` z(d~rM?%l(Kz`^c>)9|d;ZQjL&i`4Gl$A^*C?%>FXlGX37+HuCm@8HUbl-Tg$%!-%U z@#4;m<IJA2;C8Ln>CDaX<<6kv(T?ZZE6vXG=Fy>}-SXtrk>=B+^4u!t)TFuF?6>E9 zt>5$1)bp<3^XA!==+~zI-YMzWr@r3px$A%D+?T-L?&;d7!r<=c-k9s!x9Z%g?c-qY z<6p($@9N#Gyzqqc<X`FGo9x}X$K&wG<M7Jk@a*8N%jEIi-uC(CU(Mz6?BlTi=3nmO zz3t_((dY8+=Caf1^Y7)q^6H1w>GRa-^w#P0@aMtr>9p7C_3`P${_KYG?Z)Bn_g>Mo zbpQYW0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_00N9jL_t(Y$L*BsQxZ`a zhh26nvhB^vO1oLo-JmFv5|N5XBA|_nRxB8D7XcMR7F@v#0{+$QVK1_a?Bq1l^uhPT z*_pHZ%x|7^ezOAuC-YBckU%rovwx?vFI&Y|#D{0EroRzA2=QcObo3?hX8iu6kHpu> z>6stWH^k%XH}AeZ0vXY2wKs^dOT)uYiOI3?do#per1Wz++u7&Wi~K6S(tLjX{>v}T z;kSB{)N>E0r_<>=v>S~^8`><(wn0K(oX0MI??T9f0}>%=uh*M~Mn0c!0Gmiet6d28 z5R)PM`wD~wHX4nVRZ@0$Wk@2yLNyu+bs<U@5fNNE7R_?GyeA<;8Z@WzTMFbFpyAi& z{3=ViitBI*+1Zh$RI5#B7K_EbE|=Tb1ze}Y#UZ!0Nc6mdd9k!$QS|wISsB6+XdX;V zOuhR=Zf=sx+~8h})31g?q2dvUJcUEVlnj&w#N$ape-{qnT{4-vU{TAaQZ>biox#sZ z$i~K>oS5uhcm(RXT&@m##cZ|)wNxxtQMr8q$pr#|oL~`iI2^P}$JW;+qy$+HkJ#<B zO3K=rgfNiu%+AIjVz=9ZDji#0?I5jEsnmj63|UlYnl7kxY-Q!x9a~xwQW&NMl}LoH zKp`0P7y91*DTMI1AI2EY!p2zyEfzD?w_{TXnV<i;jEAu>1GLR%4T9fnRv_|@#p7Km zwAE@sh{;5$bc{nfE(~(vEeaGxB~?1MxOnW2@ran>r>FuX-EMcX-|cfhzPUN{^8+Rv z=Ja_Bx6xp5_UjnAz2I^!Y?C5FnM@`(xD9edkrH>g;)f}e$!P3B6fSzyF}>u%TO^%M mr}D&xdVb?7Cw4Ob-~0w&gyX$CR{j?N0000<MNUMnLSTYde~VB6 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_or.png b/web/pgadmin/misc/static/explain/img/ex_bmp_or.png new file mode 100644 index 0000000000000000000000000000000000000000..c22fc31eee32e53abf634278f9d57751181f15c0 GIT binary patch literal 685 zcmV;e0#f~nP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700030P)t-s00000 z003B6SY~U{Hi*GwmC%ijzrl|-kCNSbo~fFenwy-&xu<eYzUI5CbGxi`yRCLw!RNfN zcfGNBtE}k0vU-WR+hoP)v$X2Ey1H@8?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?cKtI zz`^c|)b8KLhTq7ClGX3V$M4|EiImvz<IA4o%%0@Up5oAr<j$YW&GF67^3l=J<<Oz# z(W0i_^5xc(=G3I;)upZ9^VHPy=+~y`*Qe^(w&~ia>DsC3+^Xu_s_Wah>)x#F-MQ@G zt?b~g?cclJ-uCR`uk7Qn@8rMa<mB+?!0_k6@$1Cw?CkIF@AUNa|NsAqxAFG?0004W zQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkPM@d9MR7l6|)NN0KU=#*mj$o+0 zXGv;SRwxw`6%>^SK@x>8z5V~+lCW40^I>$hY<=+l#CCS=?A!_rGtXZp&xOfP4=T~1 zLLuDg&VhK#Q3h9{B+&*8S6f~eBpML~p(b&^vn6@U$0T2m#b{8Z5cd4&_~MEE7O~-9 zf*=_4G_tn|`*$&UE0u;Z3AUi@Ws_kpcNvpsxCSJ7EW-w!ByJ(e*z+DnG*V#06sAdo z57R(x899zKpx?3pi_}}3HCVOj1h#=r;0$csmirZ0vT%(JY|HXz-k5KiT_1Ogc>-+% z*I2g=Ed#gZrj<t0Z!rv`Kl8@=x~{vp_eDR1riLU<*hLa;LR4I1uBNJPc4P0=>MO1> z^3%t=s-pBVfBn$JPrOoxdMEQgMkXTi54I4blS&e|kfbNeaxb$nGU<)Y^N;cg@O4qi TF88uo00000NkvXXu0mjfLbGwY literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..e99f57478842f61cf0582433b659d37f0c532d5c GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_@3?!2S6O@1yXMj(LE06{PXIHn!e64$cEXI-` zzhDN3XE)M-9L@rd$YLPv0mg18v+aP48c!F;5RLO&CtC9zP~dS+JaMn}cL58V&ewnH znS#1o7niJ>^>*TX*`QzgMdD7POzPaTo+w<9uwpLL)1F%W#!IqdhoMSxhwp~0@cf02 zhkMjmROfZc`EZ)w`S;|i<*e@Qr8gQ^@9R11|6Rc8|AQ9IRLjSmUOFeWtM)%%ZozPh zRpl$&!*g?h?ocgpjVMV;EJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0 rRpn4L<mRVjrd2{T7+8WefK*!<m_an0njX3asDZ)L)z4*}Q$iB}@40B! literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_cte_scan.png b/web/pgadmin/misc/static/explain/img/ex_cte_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1d779372f7fd212d2096e7701b0f1af05a5297 GIT binary patch literal 1955 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_delete.png b/web/pgadmin/misc/static/explain/img/ex_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ca051cd5d01ee2f3ac17779b362999d82a9285b5 GIT binary patch literal 1129 zcmV-v1eW`WP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003^P)t-sKLD^> zTU+Qs2lh=8Hi*I5b0^MyED5RN(19;<mZ6f8lEIHQ*N;guwdHlD$Lf$-LA>b8qFCae zX-dH9$EtPXqi$Wq>SM<0Ysctl$n0**>~+oT+Pi++y?@)iiQK+`+`oW((eK>Bf`rlT z-NS=~)9~KJgx<x4-o}QE)b8KMhu_GEk=5?t$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc z&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+mlIGK+<<^tt)THOtrLN%f=Gm0!*QV&# zr{>z0>DZ^~*{J8-m+9K6>e;sG+p6o@x9HxP>fNgB+_>rBn(N-I?A^NS->vN4y6oVs z>f@a4-@EMLuI=Ev>g1j5;;-%DyzJw!?d7rW<i73ZvhL=y@8!Vo=D_dhv+wD(@aV$u z>B8{rw(;x4^6ka*?Z)%)$Yy(c-~a#s0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkV znw%H_00Om1L_t(Y$L*8bdl^v_#f8bG-PLL%nhMc~q#`mQ2qBD7)FomPgc62MQMdg6 zk3DnFFeXNthkjrCko~Zp{O0Vn_M*|e%s-g7lsHRO4WY~igJFl-+ccRDsDn>t^C@+@ zx4(Z*ogcZ~Uny0@u)e--pf-`3sE>NR-c0Qve4jen-Zs0bzx2v0yz^33L*QXJ96n67 z-|vrMEC|8~Mm*0Cfcyr)IFAhP?`wTY`?t5ZJrIhyTpRdgGF}BjOnw=S3Z#aS8bOKz z2)SI2hh{Q9MZQla-3-V`zlMK|wO1@6q@DYg<e?sq#VQh#$r!5>kiFpjXD)tV7tH|- zs+Ce#@?tf9p@%c(J&3b~b$3yv?^<i0Wd?NOY>az?FosdP&5vMEuU5Oz<v6Z0{jh=o zomQ*WZOAT~qKnHCa6!L6FYiCcNQh7@l3<f{sKzcYIN<z#Z+<Q&%wTg<1P9CGU@I5F zAO{7nm(GGl$rxFfd0BMP$!D`Im_IsL#iN4e&4xICNNma=3fVzdXx0akb}J=xi%ub* z??5Y^PBlQ;M@VO0uV|$Gl`d%HB7Jh~V&PGT0ag%FkH=9lh;qT8zW{lfrqhr*b~zs- z5-3Jml9U9SrB6;$kZ?Mkj5>n$=YC2mx@aL6sYC-BEW?yl5z?^_b4}Y?mYDns#}ztj z_&TfPMvVl^-a$DU3E!wMhWB5?9atqzKrRj$h&b%_kUD~kp+H#Yp(6@myWO?~!I3Hu z=Fs5?L&$Ek1=NvFHk)oKyp$u6@HJeA0)gu%65GN}d$-s()mK`n1iAvzJBEpt;U*Lc zp;rPv-<A4eq!>gQ2X<i-UHB{(%b7ZoaEZkr8pXlNh({e^(G{YSM(iRIu-Pm=I9ra~ vF;TQX(RmkF9*^hhiNtoF^RIlF|7m^$H0#Fus?kFU00000NkvXXu0mjfhwW63 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..acba49c4fbfd9b871444c9e8d528deda3a37dda4 GIT binary patch literal 1607 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 FV1m**ONRge literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_gather_motion.png b/web/pgadmin/misc/static/explain/img/ex_gather_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_group.png b/web/pgadmin/misc/static/explain/img/ex_group.png new file mode 100644 index 0000000000000000000000000000000000000000..8d5de31bc129a9abcf4a73e19a48739139f66271 GIT binary patch literal 1228 zcmV;-1T*`IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=(EA5f2CVejTwfiWOA0Fgt11U#9qOVHuUhw@a(tm>9z9h#qH&> z?c}iR<FN7S!|>?B?BK2I-mL1~tMBB$bEG!w=AY@{n&{q`?&h=R*_GtekmAse>DsC4 z<DBHxlHtsY>Di~^&Wz~SrlQAS@94Ab;k>5IWyh*@@aDkh)THLqqwL+ecBwj^wTIx! ziQdJ9-ou35!Gh+|q2I`d<<Fq3)@|IrfaJ}di@s3r=D_ROwzcJZ<IJAp%bvUMgW9`& zd$dE9%UpG!OlO!lj)kjcYthWj@w~q5zQ66y&+^gH^1{OI!^Q8@)brKV^vKBY$;t7` z%kkOT_1@n1*Vpyo;rG0~?5C;bsH*3`zwW@o?yaxsud(UH#qY<+@3pq;x47%Lx$Mi# z@y^cjz`^d+)bz*4@RF6$yGLoX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0)t6JK~zY`?UZR(+CUVB(*d`NQfXa6^~z!}1Oy^sF^V-vQ6PniB6gWpu~n<K z*4lmj>zxTpNrZFE={Y_9;C#4z;o;8n<_!#Ueg5^if#~TvJ0ZwowOV^nZ(o1^02;Vy zu?(WYUYl(Q4Gr7vw@^pKIx;e1MSTv3<2Jf8Iy!1WJp{L*;juA`9sTu|@d=i7GIzB* zcbx`ea%zfYVA|z!O*g08?e>7jJHz>4miG$*&>@5fk}cqxo11erraKf0N5CtJA`kxg zXjIZ8>{QT6K3YgD<|aru>;+DY$NeBgqlu&uVVO20Mv+K3EONld<MRSY3yFkmKo;vr z%VLRIaMZ#t5Q{)kmQw~~SwrptJzZxz;S5eXn_Jw|;E6=MKJf88zXAbCN~R#CDCt$u z5zCqTb(dHyv_vdKafVpTQ;S3*D}%DOp38&oS{ZE#LxT<JgH2|$1qIUUxtyxol6lbB z@+Vln5v*J&tfe8J%N0vHeP`xj-Nh5}&d_Jg`!|S1QnN@Ci&a%El?{n)noX>UfRE$& zSy&MSDF7*1R><$?^J*E&rLBr_%XS^%;`MqgXclXlMUhx+RjbvC5!ul?)~H8Yuxhbb zEkWfnGVy48hc@|gu%#mXatCCbFywBqAxIKQNmeuqm0E03i*lu6bQyolvg{M)DW<3E zG`wPq%cPn3+4J4qJzU%0fAJC@93H(o#>acL+6g{6I5>Tc4doBgcOSnwJ9~SM-(6h1 z|A0S!`uyc9{&xO-zlMMOJUluzB3ffiAkFe$9ch*S>MpJF|I(7_Iy;r$L}JbIn@VhR z$7Es@G5cI-#kS2oefq~wwp=~2>+`>z-(ue+J2o$;LI3~&C3HntbYx+4WjbSWWnpw> z05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppn qF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTX@`Go)g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash.png b/web/pgadmin/misc/static/explain/img/ex_hash.png new file mode 100644 index 0000000000000000000000000000000000000000..9f35c76538c3a41920a7b93b94bdf97443df7aa7 GIT binary patch literal 1169 zcmV;C1aA9@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001n zsbo@(8Fi+|Hi*HY#9nXB?oYw#V#exs&h4h&@<F}n38~^Nv*by<=84npY=q5bYthWj z@xa0E#>el?&hp;g_M^vPyuIzKtmw0}>eSTprp#qVzv+I_?y1pfi`DRv*YI-8?0nAc zpxg0|)b5kj@2}wVOTX!?)@^0T>qEQdP`>AE$LX%xagvqMa+aa8;C8`}HuUky@a(s= z<azV%$M5K~?&h-b>%{Eiu<YTk?BK2N=fUgdp10_I@9DMZ-I(RolH}8n>fNlm?Sban zmF(iL<I#@k+^W3rgyPSQ>Ds94;H~fF!0zF_pG#z^7Z=B>b%2f~b#^4RQ$FKkW936b z-9bUQ>wu4ZIPc`Y=+~#`)}`#;yM|jA(>_1o$cW#@hUV0yu-$XX5E0BgJmJiW-o%9F z(xSc&4#hh=;K_*H!-U<zg67eo%w1jR)~4*;x#rQL<<Oz)+qdxO!sgSY<j$b#*|yug zf7-fz<IJAizk%e<p5x1&-i$@K00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0!T?jK~zY`?UU<U5<wWn@pV8EQt5^jN;fSkZ!Z^txZea>#3ciXMG^ue5lb*` zBLBL(BnC@M_{lzaKFl*S`~03W=gh1~bf??Z7>o&i8z-E`2MDn+LnITE(kU`Ph=my< zli!=3;UOHsGB<N!4<_g`tKc-t-v&Vskw|g>!NW(76$6NJ2r~EN>D;qx<f=ddDj?lC zzfvATB(nK=DOmtDJSQ(+N?*MuQ;UmBZ^#ftCYQ_Kk_phjJ0f{M{b7O3OfD}k^&$OP zSQlBxWkuL!wbR&Yce&O%`5J+BAl-Rq6m~(aPN&nN7W801!-mmlLX-KU#frjNP-nB* zbf^P6IMC>HI?ZTyx!j(ABM$Jw28;N7n`m*n{ee-CEij_l=W|)m<M#(C9G=C&reF~^ z#ik`>#q9t^g?o`5n$u2q89~HPuuHQD{TVq$evdr}9gW5IqV%<k!Qp^7d|{C&ZS{Bp z2@Eq#a=+Jwj-`OFxEFRI^_BMcgKP@sAf3+iBOq2Pl`555t<kJ}Ti5ID_PBQove_IR z2<Gz)Cew$9g+65OuP&+V_amCh=Zi_q93GcW`jBWYcl6^=7L(b`W$A2&nV)Qm)AC8> zY=p)*2{p#QmtU5UXB!g~#e{J`Q!Sk0S*=#954-)4+s{4^DqlQEV)eLGs$i|rXr2#4 zu8J*k#g<F0Rt+y2&1QQT(pzk$)oRr6yvav+SrQb(rKlFlofH>!thd|kzAU`IGSb`9 zXpM~`UY7p|xp@{|V|TiBT>>)4pzcQhBc}iW03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfr*~9W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a4e9369fa78c6fa19bf5c7814f8a586aed5565 GIT binary patch literal 1571 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 VFfhuORjdF2002ovPDHLkV1kgxQ(pi8 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..0051f996783873a4a27db4b971135e95cac8d744 GIT binary patch literal 1452 zcmY+CSx}P)6on&<ilC9wDWY}j1EW==VG&s^MyMc>VE_dIWsf2%OOQ>VP^3a>#ezbi zQ$WfpN-;oW2^b&=k^l*WB?JiB_w`TyKVY?Ov`?Km=bn3K?)P@ef&wq>vfO70gTZ$B z`}qW$(($7$%uVxaUUo4IW>yn~4)ryiwS?^8pZAsxthkhpJ|kUEnO0vS%3>*s%xPsS z2k<7yY&!WTdW3!iaT!ycQNDmlo}HT35l7XO3C;8jz~MlDOvDm~m7Oo7J-u?muxfr@ zpW4Z+8|Svr5=g76*J7xhadTK|9F-Zn1z?W=#EU?ha)Ykg7?VO|88jh>7B!m<YlhB+ z+ihIKOFme=tgB-K^{c?37$i!dE}kC8*Y^qZlX7DhJFTT%m|NeG{<NMuQHSGZ&NB!^ z;v%k3I!Km}R=5~+lUn8L%?)9nD0kB+*n|W|{W4?{z}f(LBJsvL7vc+yV)2Gr{Z1in zFoNuUS%J~8tXEIz)ik||2I-d8IN-v9etFrj#(`wAO|24dG_VI%MS2w#P*Oqdl0sB3 z7yho1^%ArX0Ocg0m;^P88U<b>@6$+o03~@7;%^vuMm@JJ<aWoNJuAayg^%p>Gmnsy zuG1*Xb4;BYgOU392vO(P&!Kp6@p=_SEyk&Y-2;lk%6vCay<jj&HE-0dOV0b0N7*Ii z>@A6~WuE;;C#7g56s?$SP%?QaR1+n-c`~kT8uNVa*2|@o?lo)=KN~N}8`2cd*w{>1 zTTgj<YDFZyg1O@D{UE}YyxV#N4ySl{7?kr`5m_T5X@ui?`P^!3EZxhC>gh@L@R+)G zO(PhQvf3nzE#>#mKw1u{SyOTb#j{N!#xvnegJKyEY1bgl8X%hmqzq8Kx;j$0LMUJl z<qK%_8X-v|7+3Q~)m)Q^fP}#wDqs)hYxrZTbs`|9t4#~%jZRFLv+$sL4Uo=)sui7h z#-L;~yHiyh($Tl5Qd2dzWCRC>z`VsQjOo~s>UR}uO21G3b~5>_sl;f1pL3yp6Y(*2 zTg|QPYVFdf4n2i1ryt-~R&&EyEH~GIaAZa|e{p<ldYm><(Ym$Sy#1kbWFdS!sl4#8 zg+-&46R)?p=v<IrxKAkB`h2<TL4-|Z@SI~R;xX*W)A-68l_8JKw;U~tw3<);5q%L& zO+WVhmV94&T?E^GFg?51+bpQUzhTmQhVhm~3Z0o+9h<ZCwR#@S#fJ;<<Zb)oT##J| z)~QSg4M#(dpu=3@PP3E!chc@*v$C?VU<{A|;Ea$C)Mvphc3Q&ID5^bSMg}7&YYEw! z+G=rs{cXF{PQvQnc;JJIsEn$r4gNJx`JpL<IafAY`AhBA`O0bGjYCz{Rlhy-wHk~D ztSrl;%8Mf2s{-cqz(t1-!B^mBiO9Ppot??{A(!2P0&-5fl5P>dx>DZULg*TK_Nrt5 z-2iOB@sKY=Jc0s3a*{6G2s_h?5P1!wrHzP^j*5=&P&pEke^pz|yOz9TpDUboGQjBx zMo!1otB@1eyV;Rc&(=*V+v==K^@N)awupf0xSm8APIR0a))g^~LD(V`iz%%B9lV<9 zNW9qx+^!S-`8sx=M=9LFn)pSWRENVZslD!B8wv}&N}w0~Q)Iq<_h*6eL%R>T<xbtB zHVKX_vJbiD$PIhPc3|ksSjnS-lh?8Q_gnrdZaWp#?-x#cg*}W&rboNyF#et@q1F6p z9T*>0alj*U0b~~`wx_Vx`_n~Y1o};*=weXmz#wPa!-WHU)K7MW;+k{KB^hrTOISzk zQem*}7uv?l*3EgQg4t*IhG!(iW+b}Drze^M=7@AaA{-nMNQY2Iq`R||yR-9g<Y{*# t(zVw9;QxR-DG5oKoc{o%+b7`Tw>#41KY&_u`GpC9`TGX?bfIFt{})E(L^%Ke literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png new file mode 100644 index 0000000000000000000000000000000000000000..76c546a4dadd7fdae310dafcec2ecdef9649d4c5 GIT binary patch literal 1377 zcmV-n1)lneP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006>P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZJydFPPaY zjqWG6vC4&kzm|uj!nL^a^ZV4*@~N!lj*;EL!|c+nY?{_9i1sFWzH5(?-O$nT?A*cg z?Z)orvhC!s?BcKR=fQ#6N$usa=Gm3y)|2GZkm}s3cd&fiz>e(VuH@B`<I<1f&W!2U zr|sXy;?RxZ&5Pj5iRaa&`u6Vc<G$$Fr{~tC?A^KS-n!+`q2$h=>)E#4zJS}je%iZz z<IA4fyMEfbeQRKz9{>OV0d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U00K`* zL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U6fJ!G0)j%qd?aZR z5fu}c7>rs-_lqPS2uKb<h(XgGuGEK33lp=Hw2Um1oV<df5)(cx$|@?VY7i|P>Kd9_ zOxilSdivP3!2P0PU|<N*L%<e9h$*WW0rh~yjKRJz!Ik=uLrmGoKm|mbnweWzTAAVs zOBC;`SVOd!+t}LKo8n3rs9GE#S{$96U0jLO;s(*;?&0a>jav({i+z0kltEhjT>}Dx zaQX!$jRpIKgaY-1nSww#aj8!^Gy>=})5xgkm{?PyQeSXrL>$l-)A)qMq-30aK}mc* zDRE%Gq^6~3Wa89<QYfipK|(A$CpRx2w-)50Po)5&rLZW!xCEzPP;Ds%YatL~kR)gf z39qtp6+&Uk08WDD=4PfK4Ju{j6{^H&F|VwwG&cpi3aCSkSS=P1TU3bB0n$=sQ*DYQ zQd3)3UtibI*wozI)Y6L8FP3fY?MPZWI=i}idV2f%Crq3;Y4Vh*m|7qK8ivp@ZTgHE zGiJ`3J!e`6kUM)8rXJI|^X4yD2)CuC6QpC&l-Udnb2@84dZu8w&2;gSrOTGXwbXV2 zb<9{X8N^;$3nC}CU}#yjdd=E(a4mJ+AT3RkK<xE(AaYU@hL*q$8#ir+YpL%6X=$Da zVsEJjkrSISv~1nBJ$na9TF^p_D2MG#-nDxVY2M$pci;X4qy_TsgNF_wv=9}Q2M(cV zAtJ$;mK->6poFAkiJr!&3jm~}-@X0I9(w=)03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfh#BXQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png new file mode 100644 index 0000000000000000000000000000000000000000..ba24ed16aeb0d93bd133902b0b2218e674f84528 GIT binary patch literal 1402 zcmV-=1%>*FP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006^P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YN)&~ znAt0h?kBgg%7uZymWQOmwYc*0`_$F)sjTIWk=?<=?9#1ln$|0b_9lA1YmbuM(9!Yi z+`;qh#_r~_?c}iR;;-=M!GYRI?d7rN*_GwiljPHo>fEY#uzcLWj_l&D<kgYm(vRZK zjOo~??cc`Y(2e2Ei{Q$M=hdb9_U`ZFzUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyHkc~n00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~ z0%b`=K~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4 zBxw;56%&^jj9OrRk(88VkYoTMLO_ZS1f)P}iPb`eEpWepZ2==#y2F+Fuz8<}Sz1O` zj!9lYQAwEzpB5EWRW)^p77h(fEo~+pT|IpRY+B&4uWD#$1kppl7I=sOZ7~Mw0g0J_ zePN0#^&zJ*6=OqH5N&2|VQFP;hAZ`<cwf~9qQ%12&fdWcSGqve;t0{=<m}?=Mx+*Z zh!zh|FK-{*T994r>*ucm(h}en7!-`tFNhEWf)M}EFrc1rGZ2VCmcb2F!XklAGmDCj ziH$QOD!+z=MaBbdF-u5HN>0J)7nH>3n;H-HOImtHW)@B@D20-0HYCJya`W;FaBD#> z`cw-cT8fGbN=kA11=W@^uoeO#21$Y@knk$6P$d+m4B#YaVPS3t(x6&iQK?3Z7K^H? zDho5PtAIMxiPd5Wu|<_A9Uv{$wl!u*BDHn(4Gr~;P0cMW&8=-%{bJSb(Sf9;v#YzO zx3{l<!o*3FCQq3<4O0swK*JF_rq7r;bLOnsbLLL(1ajxh#?)grZ~lUXi{Q4@c7b#( zo;rttVQyC~NY7LZx0x+jx@`FhxR$zZppKa<r-0b2>Oka_Rtznx*Q{N)9<HUn2c)HW zGKjsQ9z;%V#?TV9ant54a4ikJAT2GEK<upzAaYU*hL&yHcjW9ONefzt5#_L5DZBUV zCC&T0_w7G$khDPFbLjA4gchQr^59_<Ekq<3v(keH50;XYEYZ^#bpZet8{@o}32r3- z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f<D*lWB>pF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png new file mode 100644 index 0000000000000000000000000000000000000000..fb536b11b68fca6c2feda14a8011003678204d62 GIT binary patch literal 1389 zcmV-z1(N!SP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006~P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZLlAj_u#Z z`u6U(vC4OVr-z4&!nL^a^ZV4*@~N!lj*;EL!|c+nZ0y{@kCNSe%Uhb(E6~yL^X<m& z=CbYNu<YWm@aMsZ_9pG+vF6#8<<^tr(~#=is&%M_sJt)i;;!V?k>k>j;?9ie*r$Ha zR+!l<;?RxZ&5Pj5iRaa&h3hnp?kDf#zUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyg@M18hosTq4gLTC00DGTPE!Ct=GbNc000SaNLh0L002k;002k; zM#*bF0006~Nkl<ZNXKJfAR90;fdC^ZT9}wwSlQT_NYcW=$;Hh>nikS+;RXAJmlQ30 z`~reP!h9rY5fK#=ml%v%NcW2*9|%YeK!`!p9j?@eO$!sVl(dX2lbpPQq7oB6Ey^k? zs%j7|9O@dHT1?tHx_bK9w7~tMVqjnh(L=x%M2IP?7y<Qw#EikdFu|4jkV8z_$Up@| zo0^$hSX!Cl3QH94t5`#{nA_Oe*_+}@7pPhsAX*%qoLyXr)Zzxw;_l(;<&9elvWtCu z{ggpk{9OYAgK+u<C5;99g@gk2gqeasIB}^@IWz+3G}Fka=$KejqEcUQXha;)7Ss5I z#H3`LenClmJ}Gfvzoe$6XJq2kf>J1{WI;kKJ0~|UAGa3dqEDp&qNT7XzqkaaUr=o+ z1#2M?Vvr<g3<<BYauq^h$^cG+=H_OmAPp*I<rS*LXfdy>tTZ<Ty9%g7jaV%f5L;A; z(gD&^Wm9d6BvMmbS6^S((Ad=6+|<&F)i0K9?(IlgIy$?$dwP2N`X@}BIBD{fshC<I z0UCzTF>N}KoH}FXtZ5xU#_SoGdQ9icoi~30+?JY7kdD?VGZ!wL)ma15GX=wKri&IY zS-K3arM3%1wk%%=1S@Jm?8z+{T2`)Fy=E<3OI<gJY+47>vc3+)p45b)C2+&WO`G9b z>U%(B^A?bnt@R-G#AXaF+qUn>-bs=cv=Af8VY`xd@7YV5_jm8xf8Zc#fxPF?;ll_m zL`CJn!zfx{3FgRAoC(IX<lw=BB_t(F^fX3Y007N*+;lfqX*B=<03~!qSaf7zbY(hY za%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0 vW_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfuI2JN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0018157f64a5ae601a2db08fb1e4a553385c33b9 GIT binary patch literal 1417 zcmV;41$O$0P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700072P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YTUq% z?cc`w_U^Z_%6EXLhlh*8wYc*0`_$F)sjTIWk=?<=?9#1l?A*bRlHGmFTbkA@(9!Yp z?Z)orvhC!s?BcKR=fQ~fChg_1=Gm3y)|2GZkm}s3b*P4@yf5tHuH@B`<I<1f&W!2U zr+&{?nAt1h(2e2Ei{Q$M=hdZ!>okq-C-39F=-8*{)}`#-x$NG$<<Ozz&Y$bqw%ope z+q{0-yM5!!p4z*9+PZy(fxniAqyuE0`2YX_0d!JMQvg8b*k%9#010qNS#tmY07w7; z07w8v$!k6U00L`CL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U z6fJ!G0)j%qd?aZR5fu}c7>rtAevy=vWRPS4Awock4+Nw@YKhfChAnWvfNcRISh~ZN z`mlMQiCJ1kR*p$tK~YJW37-}fRaG^0h!zeFO)YIE9bG+r18iF0v9D@qXavziz!rFj z0c|k`>H&$FfPG<#EA=6#F%@G&RS<1vZeeL<ZH6oLp?F`_2BO8n*3RC+3|G29)#3=z z;^ge&>PDm%cZe1bPcLsD+**)b?Ca;R0@4!T78n$a(=Uh+1A-9$&@iB$a5E5yK$gJ` zRKg;GPBV*&j){#kBPzd!ghj>!Z81woOiE6{=@*p5=bIW2_DfoNMrIaHEhvSOYBnUq za&q(X3vg>eF8WjpAzF%x3rb3H`UTaNGO!i`AqGi;CXnzduTUivrVQXDXklS)2GXEf zUQww=j24TkswxXJu&aPN)QQz%39&_$C><az)wVTeNFud$^$iX6jZMuhEzPZMSp8zv z?$LpyrL(KMr?<DSf5OB`lO|7@It^0`BtXLvI;PJ6lGA3+nmxS}$e1$|Q;*r)dGi-6 zgxgZv1=7(rb=IOqv%6|RdZuEy&1~_KrOTGXwbXTk$kr8$fM8`Eh&`nhL(8hwYu2uV zYpL%6k<IHtS~k>!*pr(vv;=M3w0R3$OG7V+Y}pFZvaJEcp45V&W&4huIlD;Gf)-*# zIc#^zp1u39dcPZ&_xJ2SaPSamfxP$dks}B#L`CJHBPd#63FhcAoC(IP^w6P0r6eUw z^fX3Y000U{;7!~3Lt6j<03~!qSaf7zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4Fh zG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bN XH99ab%9mBF00000NkvXXu0mjfCZzUl literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..3a78fa6a1d35d8b2666ee3ffa5583db9662a67e4 GIT binary patch literal 1490 zcmV;@1ugoCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70007fP)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j_U_>5)wA5djnuJo)yKTSzu&2=<&>D;#mDaG==ksIwesx6?A^lL!H?z8tMcd6 z`}p$9v%Rr~oVtpQ(zUVm_Wa-A^}oUFs;%YG((&EGk@4lw_t?(XP%76v4Bcit{POSI z-Sn%j=JV~w?&h-X<go1Gukh!=<GQ)mQY+$cP1;Eu-)lwf<+0}3mF3ox<kOJq+^Wd6 z(8ivy+*T~?;;!V?k>k>j;?9ie*r(rPJ=a7P;?RxZ&5Pj5iRaa&@3EfMdPDEyzUbJe z=hmg{-MRG3zUrWd?4*wR<=^byy5-QJ<j$Y#*|yxifZM!&+Pi(@%bwc1e%iWy%Ued< zo^8}&Lerv`vZEDM00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~0*y&T zK~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4Bxw;5 z6%&^jj9N(dizFWiNDe@VLDL<s)Q3$A6SI`Gj4YF!yn><<6Fx1<Dk`dK5G@?)8k$;6 z+B&*=`q;F<{i0%EU<lDez!pS^DXSO(^?<~T!M-rTmHLoFOxegl1w@;gnOj&|nc@md z6z{88L$sLN*xK2f;z}2&S{xu+9G#q9T#3};2GQc~;pyd#TMM#_eSH0tL0bG>0|J9^ z`UNG81^b1B0`-KMf<QQNsZTjH0_Zf;$f)R;SW}`>UvOwd9MBfi_=LoyWSo9MNqjyj zabUlsrln_O;?#mtD5+#YLM%HcH!mNz7UZH&r2wL(uqeN{1gBq6Z7Bt7ArNAaBxno? zud;F#LSf1PPJ-s<W~LwwDrMyrs>En9udJ*zHwC*2s6&ldEfx@4REW|6(o$tpZHgpP zQ(ISGU)Rvs)ZE<E(u&nDmTm6sNLo5NySjUNdi(k(Oq@7r@|3BVS|9-$hR`u>Is?Ou znX`ak_8bO=x$`jfn9g6YaM5D8Ej67$9SlomEnT*J)~ppk=G-Y5ZZloEYW146a4of6 zAadP$28KBsX3YYzC%0f|*|=%*maT9tb=@GcX%djwHfuYGJ*f#pOW=;3yLQ91)c1hM z=7|gpduGkr3t~@f#?Z2F|AFj-7+MZ(n>FijJ$5Z<AqI2Uky*2jcGux>*s<i}Cr+Yy zzhyE|3qw~e4(}g7b^6R%v_Nj1GM9m2dS?xeKt6Hq{CR{HNK`URy)bLm#SR7>QF-<} ziWX>sxio9mWn2lywB+pBvn3=YOY}5GT>t<le%ij3CAg3P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f^-`z-2eap literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7764b74f5e5e5af1a205b2ecee9ed184727e1fe0 GIT binary patch literal 498 zcmV<O0S*3%P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70001NP)t-s|NsAV zbaXa|!Dg1x!H+h2o~cd1>4~}9VaDrk&F*&1?7h9crNQLey@{>X>89TD^V}-D-R=M0 zDZt<E!r<=3;qS-e@W|uv%H#0M<nj6DU(Mz6|K?xO=kn9&^VI3|*6H>3>xcgAhT-q` z!N@d;00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0Ut?3K~zY`?bO>2 zf-npQ;7O;V0?Nb_&J(=<J35L^UDqjzCdSySWyu#<`)@-0>*s42VGTQwXf%l9@iclL zNdOXeuiySypCM4!;O@y&X{wSOIUXq~XQs-}6QvYS4hKrA@L4=0l~^f9_IpA^Zz9B` z$BhkkJMf8s@sL*VhLWpb4Q#i-2+rIQ+9-eP?noQ0lYBNH*ld8!i7ZVDly=E_-I=Ub z0iwNRxdislWu;A#vn&>!J9Z<@Ox#J(okv2`=*=e-1+Z!K=krEr8ku~;d=B=YX>j2X z3`^5Z>~y=h^w%!z!<XmH<A-BxricT_g}zMDF0MB}&$8Uyetc9c(E*Y`k!1ybMZHLj oF&RsOM{v$!pYbjo``5SC8S!5pi4Z+;&j0`b07*qoM6N<$g5#I=_5c6? literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..d44eff429fa9a3409776ea88a11421582f6f4598 GIT binary patch literal 1298 zcmV+t1?~EYP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001q zx!X2~!Eep(M7`;C&hL59?^VL-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUOPl=ya2odY-AJ!Q^I^(ZP>4@#=@|<6!gf$nfm8 z@9DMj?Zxiqv+?W1?BlTT>B8af_vhLx>g1j3<DBW>n(yed=-!#<+?Va;vF6#7<<^tz z;H}o__3YxW=GvC*;jZM>lI!2C?dG!U-mLKEz|`sV%c5A@y@~4Gs_*2!)9CZ$)RE)T zkK)jc>DsB$=kny!kmAma@8e(T+p6Kris{*?_Uni3;k?b|^7G_h=+~#{*QV{@yYAa6 z^V}-n$%)^{h~LMD=G3Ii<nj6DU*5)s%H#0o)urasqsZg%{_KYD<-qLSy2s=2#o_P& z=3ngIy5`cN=Fy_&(V^_zxc}ZM-o%96!-L$xg5}Vm+`fRq;O^wkpX=JUz~AoV&7SJn zw!Gc#+Pi+^%$}{*>Ep|u5BdaA00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0?A24K~zY`?UdPD5>Xh3ZKAN;Q_C#*KwubLStTT}1_fLIkws7h8A(MzWmN>> zU-!(C!g1n>o1QNGE)F-m&yV-_9Zp~0%lzwkMX>Y7Qw$+qOC*vv#9OIU+E4Vqdp|Hp z3=Rzsj}RlHV`Co(QA9F6K0ZNAOioUIBtA_|O$`u3pQX}aVsv_XV2tRNGV%8*U%21Q zpI@J!9p9ai$!5?8$Q25O9A=eD<t)sqR4O&7Ns`onhN37fbRe?1IT?#6=I7@Xpj=p3 zRDo(~X=xcqonCJM%4js1F=S<>16kw|9SNjfucyFbG<8Q*i!8FN(;>v5|7N7XYFb^j zi6er`Z;S7og+&Wmv(4_nkhL`y`2p<k=g;S-7$T&omq}6$8iRq-fYxd@JHSEHv=d8N zUvG1Hvaqlg8+M>wZnp<RHaFW4Qm5mKHCn;Ey0JwA?RIZ>L3V^<DXv)CmdizhcYE9C z7f0lZot<3~3#Z5L4`9gNUeAs32*`uMAWESuRxLPecC-tp*W+<QAQTEmL{lKRzaI@^ z7CvMViX9xrG34k-K%&tED%OOq2kmmXz2Ncrd?5%Q942w(_?SncEW#FR7mD@!VzDr! zlF1~4AtxssvYSXG(yRsji?awIi*PCekvPMgV#wK9&yAg*b1CUWCX;4&;YGXf`$GYU zq~h@lIL+qrmmrE{uCA^!xWzRCxk9m6>W1*wBNU4rq#&NWE@UBJES7PkQfWgTi$%L& zt_y`cl#1nYRUAoYSeFiqTrPhDH>GOz219Oddv1(Jgp@!yg?4elFxgYMER{+qrCO`q zwWpwmuU=;#Kf#5+9!!C=D6<x|Mx$}xj>y*P&1N0_`voL*$X<^uSL_qg>P)FLo0X@O zINC)Pazz%YmdlMA+~Wvh&>fq3bh%)%n8jVI)w=6!OnAn7Y3ybGuXzBr6b33x=w6}# z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f@j>KSpWb4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_insert.png b/web/pgadmin/misc/static/explain/img/ex_insert.png new file mode 100644 index 0000000000000000000000000000000000000000..862d837277c99e17d2b66232de79fce010752e7c GIT binary patch literal 1065 zcmV+^1lIeBP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003yP)t-sBmgK| zTU$1W!3nA2a+aZzl9IuXHmaF8ou4@}wdHlD$3eX4%c58k;}QztMoPfx$EtN*#Oh<l z>TAd7XvplT#d&Va>__Y%vc!A9!GLwm?AyJ6+r5e0zJT1nfP2yJ+`)o`(eB;DgM`!Y z-o%97#f9F+hK$ti-^YjF$cT~E?%>IZ;mnGc+417ejN;IZ<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp;FQ>)N;I-kIv%s_fjj>EN2{-mL81y6fMq?B2TU;H~Q8obBJc?BTBM;JfPNo$TVT z?cu!a<FM`JvG3%*?dG!X=CkkR!0_h4@94Ad>9z3a!tm+B@a(qn>%{Wy#q;gP^YF+M z!Lnrl0004WQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkQhe<?1R7l6|m0NSt zP!vXK&`lBB2CJaOTA)a|q(Gri2tkO1TjWv@3IQV^xBmZM;7QKm5)32GIHM2U59@)+ zO7{1iGlRkKH2+{;P|ED2o<i9y7RwoRabmSzQkSo7wrlG8!sWW5Zmt4>Pn51=F&d2) z>IBhBy)v84HtG!NF6!#^)E1!r(pR3TJMW~P0*}+_^l{1Ycsz%>EXy;PNs=@H{0soS zsZ1XpT4Ta-wOSp4TqzX#AZ4@ZCSYUngQhh~OI2D}smLG~3Iz$e+4NHRx>yYJuvW$` z^<kBxN(CwX!so06?Q|;DAWA+@Hy5zZqVB&+@l8$9oxr5os0~RL2mO(muAG;k%==v= z?{&03tR0w-WO+_F>-VJ@Oxn%n5Qd^C4wf(0IAs5IimsC4t_ET>94@Z+-*8Z+6;vrE zDmL4OX6o)%1Th>A6*p>99W@-O6jM@*ZQMqqB9uZQMgW7>p*i#m+5guRgQ6hxVDr$y zp&Tmg*VxiQ7K(#Tq1&Di4jVOe7K2i;IDj6{=Q^OhkHF`j9~j8~+7t{*!3X_54z}(v zzyVU)=`^|+m|`><E<urD7#?zdpLbg!qEcy%5Em;j!C($DUayzcSJ3|AcS0pa52eUu zI?&-*wyvxEL1XK$h+=6#I1mKB2b~PZ-9tT@h=0*v4DY{{!oxzs?R3WU6?`!;`C!nW z0nY1jCn4^1p6^g_rK@7mS+E|rI}S1D`FTWN!TW1cBogs5lw*-d`L~U|Gby8??pJ!b z3_1msrXytzkCh?RRq(}7X*#mo?MOj9Ce&3jKILMl+*jeyDI_uXRqokjvW~fDmd(cA j94hm6lTUy1|Lgn&xg@`Em^A9100000NkvXXu0mjfS$;eB literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_join.png b/web/pgadmin/misc/static/explain/img/ex_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c391233c449bdc5a0d52d50f522bd3e35c649c36 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_7<@W^2*R&GEgz?Z3h8!ou#;)brTc^v=)n(b4kM)b!xs_i~n@ zTZg#3z3iu{=c=sduCM9E#_!9_@xH(9#m4Z~*7U)THuUky@a(t1!S2S#@6FEg-rn}> z=AWyq=(DuyyuIzz)bo;+(T1sHQjHmZrCYPXrlG`Mg|bG+s&$Tqt8$|?qQ_wH?6#)N zW$Wdh>g1j8>9p_bw(sb(^6bTgsA6`iJD#<NuG(>Uu0Heb#_r~_?d7rT;;-=M!L{Ui z=GvC!*OTPakm}s3d$U61)sf@UkK)gb>DZ@@!Bgwrtm4p);mwQS%8BRHr0(Lq=+~y~ z-MP8zf4c61<<X(!&Y$Yow(R4uyzqqFzJS}je%iWy<IA4v<DBW?o0iO7=--*_;H~M} zsqpE-@8-bX#f9C$g5=GfwL|Xa00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0r^QpK~zY`?UUJC(?Ar(V^BbpRmDM2l-2b%E>$$61+gq;DJ?Apx>_)8HEF30 z1qv<yI!QY65i<h=Jn+JOn3sINdveZqt{_~`MdpTR4te<yvEk;e#wM}(cFUc+BHuEx zwXMCQQ|!8T|3SCNw~VdAT=visCNG}~>Uq@L_ZU6tfBI|y*^ohN&5&~$8Xg&a{sO&x z)%W_19RZglNiNj$_TBprh!c_AZnuPnKYkkfd})N~g^7GY=8#tqWQ@OlJIjk*1$#W> zgqZ+yzW-as^djR)gE?nn@}vi!H!=L<1mfjN3{M>+(=)SYCw3BX`FwNp6fe$M7+;i6 zP0Ts|#ifABKyWz}Ug1&^<UqvyH3+S)tw$+doagEfL}HdoIG#wRD2Vfr7JgcU0O^g* zUkVLzoGXry#4@R@lB0NWs^H)F^p4ffmArN24^hdfs+Omy80GW&f-oN{gjc}IE4D=t zwfMKBQ@nt8X1hFR1{zO;+2q*P4r#JhD$x<&c6oOh3TyF16wJRei2A*N&O&C(yQ>A* zTTdh_V86<|uIp4UMlA~aa1gDeGGHqKGqL&y^4bu#%6@n+eE^xPqU7u<Y%fNWHY$*+ zR%<FRl1?Nyv!GOKHH{aECXMoeS}PV0|3jEwtnxul(+=~OPV9QFW{v><WVgBso0Wk8 z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f?exDGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_limit.png b/web/pgadmin/misc/static/explain/img/ex_limit.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3efd59d70436349e5413f8c5d2673200cd74f0 GIT binary patch literal 1237 zcmV;`1S<Q9P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(M7`;C&hL59?^MF-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUNiI=UKt$YscuhV`Hfo7w~d&?QwDGaB$~uaOH1r z;cjl-ZEe|XY}0FNhN)yyjTym@HuUkx@a(tm>$dan$M5O1^X<m+?8WZpv+d@x?d7rY z>%{Ehuk7Kj?BK2N=)$7LVC&_c>f@a6>b2?Mn&;e?=i8R-<FMt|ljYTt>))-W%w_1_ zndaG*<kXSm(~#=js_*Et=-rs+*p%bakE+va@8-bo<iD=jaL1~3vEFs<<gn}Btm)gT z>Ds97;k~rudA8?#xaxo6&Wz#Ai|N>>x$A)A(2n5BiRjm+=hmj@)urv<yUl57?A^NN z(xc|lqU_wb-^hpG#)jt9q}{@U-NAz8(4pSMh1|e_-NS_2zJTP;pYP?s>)N;G)1&6m zq2$e;<IJAw*|yrdedEiX37wJX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*pySK~zY`?UU_O5>XV!X``@E)R3}Nf|O*B$m)u`ByS4@xQIz9FPadbCWy#_ z5QxIR-d(t0;9^epp=NwO+}WKuzd83g&$%MegZ^zjB6tlvg%IMgSS)@*Je5c!L&VUt z=h9(fctj=}B}T`_$6pYFh*&O{i-`$^Lh+J#H90vcB}QJqnUWD>)6>#%;<hdmlBqj% znNi+NGuMdnZJ$&sm0G1%znh(%otvA}Xf*GU=I537>Y^pJA`vX;bh-upT-1Y}qNpWU zrdJHBuxd1!Er6>!B0rD_(XFkm>CkDl+JLg#?KIF1r;`Dr%kB06uIeHmuaQNo)k-16 z>!rcq^!bcncKg>^z*Rzst%U@<-VFmVK3~uTX8-!;P2>~V_R@9{;9VHHF1A>f4FRs| zBA?OE7vMGU#8sVnk=rDx1^uFp(!)}Krk7!LhhZ#WF?+&W5Q;>jF~C)w9^1QnUrFAD zodO!W2)fMJMPxr7PXMm!blKhehPqHzyFCE(hQql7Owi>vLwGZpj6gIVPo)7@b#KOh z^I4$5t~i`N223uuKMZVge?JO|R4R1<xT-gO?1Jfc5lbH&9`&dHC!2h8X_3C)(ET>K zCEkTm$i;CclRW{Uhm5oEtZyb+ez5U09OO<<^N=|!6gXkT=yIVYXK@xOl*Qp`v6z8u zp;Q`xnA|;C<PITUES_h9E0xL>VZ`DIvp*md{nbSlxu|lLN>vc~?IsI!LGL0Gf><J* zK7ylszIF^J7aUiGYNdX8C48}77w26U^+u!76h_)hp3ddaU~A`Rg$v-yWrSP~M%qh` zvMAR0EYM&p<#MBb8`9%~Yq_ZNF0Pu*=GEVt*n|Fa{RGa817HRj*Pj3Y03~!qSaf7z zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6W zZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjf-+GHC literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_lock_rows.png b/web/pgadmin/misc/static/explain/img/ex_lock_rows.png new file mode 100644 index 0000000000000000000000000000000000000000..41c1148bb185c87898b3fddaa76be36a15703336 GIT binary patch literal 1520 zcmV<M1rPd(P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700078P)t-s1prKL zYin<9ZE<dHb#ijIWKo23T)1UXxMxwgX;FK4c)Ds)x@%E3h{3vUQGR@Ux^Yo}etx`j zQG<Yhyme89f`YwxQHX|yzI;)Nh={*{QH+X;38~`0f>Di(jE;<qz=Tnbj*fDcp^%S{ zz=%=8h*6S~l9Q8@!H+hYm3+dEQI(aIm6n#4mzS5An8cD%#F$YswdI<go|~SYb*9Ih zp`pT_QO2H8o};6lq@>5AQ9-=u%c5Axr%}nMQA)t+%BxY=s7}hQQOB=S%&$?Wv9Zju zQmC`DUBv4BtpTdFwW_wZW5(*uwpDA#=xE67&bnBwy1LG~S+BgjZp-YjzP@$M?Ap72 zw8FyMy@}(!bKJgw|GhAK(eJjz#N5GxgwgKZ!-Is=@ZQ9P-o}QE)b8KMhu_GEk=5?t z$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+m zlIGK+<<^tt)THOtrLN%f=Gm0!*QV&#r{>z0>Dj2~+?VOvsp{Fb>D#L7+PCQ5nd;rD z?A*BN;F{~+tn%Ha?A^NS->vfAr|jOk^xmoL;H~Q8ob=zR?BTBM;JfPNo$TVT?cu!i z;i~N8u=L}t?d7rb<gf4KzU}6+?&h=a<-qpkvhe1>`Q@?i=(G0cv-an-@9DMq=d<wX z!uaU6@a(qs>bm&qxbf@6{pz;(?7H&p#rf^N`R>2@?#1))$p7!Z`SHN{@xlA?!~gNV z|MAlO^v(bC)c^F+|MtiK_R0VD+W+?3|M<<SyU{8D0004WQchC<K<3zH00009a7bBm z000XU000XU0RWnu7ytkRE=fc|R7l6|lj&CyQ5eRxeH+_N%WSus*<!m=*`Bu8B8iHI zC~mlcpojwm1gMN_hN04AG^HkyMp;_fzWiC;xpx#ij-Jk`bLxZdhi7KancsQe=eh3< z3Yw{ZPzMOMrc^$J5DEl>R3a-OF)@e8xgr!66UABC*%d@ZUSZ)af)^1)L_`RP1gMF` zrP$b5A(0C4Y$7i?Sy)K?L6_Y-qqanb<M+*I<|&mUcAZbVnRe~SO7sCn1_lO3#?<5S z41pnrVSK<x)3g_0A|~ZR%)0Q%xVS|K8R+b6_i*ZIY;5cUjNNMO2DH(rb8yJniyPR- z(tX=Gq#Ysc7_l>ev0AM(=rZcYkf@Xxj4t0ln?*eB=x3yTb~{A6t+$OdaO!GmS~0Te z24{TE!C>SC%|Gtq5pvPx1ztyMQx8I}?^v_?^qCXK;t$OVo);YybP}+Yfi!)xvdGo< zqo2Nf{PF$s@L+%cR@fzzEilx_FhjuC-A(&|*XeNdfF6pX+^Eatcca5>4G#A9K3UHq zNl8hW0WP{&7u8LGQYjQRgq(YWkWm(S7&eYDb~_H%=md_M>PiYw3PmYKPQCUc4?_J2 z3YJE}wpOZC6sRjLm0J*U{FNWMzhd0WWEXCm#o|Ip{0l#FH{`bxJN%qQMiFvnG3?@_ zyPRH5ds>^|S-9(LHaBpY&8802W$)8xFF$<!`R#4*z2@cx5W(|LbRmZ>%tZzHdW7tW z-nMaVSm>%{Axjp{p9>MEP6rnQE2UB?>VQoymz#m9AYY~jd{+!b+Qcai)*>$|G6923 zCL{R~I6w86Q`UtGx-c0!K!=_rTX>P90f}WyPLIC}Mb){v)4|$d(Cgbki&j(Bz&{wC zAMXHG=pvT{8mUC0=11^i1R{D_u2c)EBogry2#z!mA#<hDDxj8##Y%p}ZLyeL6TGx& zG*$JWUaeHt|Fy(iCIdVLtZgKzZ2=8xwHkI&mY3J^4~7>5D=9@T#H@>Qkw{d=j~MdV z#lWgX!TOOBenbyXLCdK|!XiqsSX2(mrbgOGEu0@~po`j)l9JkK5=)=%R?gJ_Sib;} WuicyymX%Qe0000<MNUMnLSTYGrAb2o literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_materialize.png b/web/pgadmin/misc/static/explain/img/ex_materialize.png new file mode 100644 index 0000000000000000000000000000000000000000..c3bd0bb90dd2ef1cc1baf7f932817d1b6bdf463b GIT binary patch literal 1221 zcmV;$1UmbPP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001^ zyUc^E$aSX2Hi*HV&EAa1-IK}Ps?y-H)ZnGh-mTK#zS!b$%<V(H=}o`rQ^M+n)bNzp z@OsYdhtuw@-}7s{*>k?y5Ub*3#pqna>5|p&pRKHao1$`-p~$a;;^52R-owF<HuUhw z@a(tV+qd1?w&2~u>*k;8<eu;8wd&)Y-PyJ2;hXR1v*6sp^6kaUy`#sfb>G{;;oZva z=CbkX#N5}k+|{$*+Q8@Bm*&}&?BlTA*tOf#vFYHN=--*_;H}=+zU0-B;M>TCsbo@( z8Sv)7tJG}W*1h1`$FJLRv*CB}=)&sVtLfaT?&7`L(XZLhuG!A5qQzgO%Ve<JbGPSw zxa)u8(U0QJjOp2^+S0Jx)VsRuf#J-G=+~#%%&gqgy5P!*=hmj**v0JKy4%va+tIk@ z)THLqqu0r)-^hpF#f9C$g67eo*vzZg%d6JMsM^oB<j$bnzJT7<!|U0$+RnGy&9~&u zp5x4(<IA4a#irW2ecQc%&=gc%00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0(?nCK~zY`?b6p*8bK5XU_ww#jGAI1rVXt0A|?yUN>Pg78bgs7LkqpPC|yAQ z^~}hc;|y@}z&Sa2@IKs^*>CRt?k<n_Q2(eN@lkOdJ9#WX#r69K{Ds9u;S&GJ)1~ES ze2fTIR@a`t5WIY~zW!Q(k;OL~8$t+$3(Evq6^TTff|a$mo9_g3PI><U71uHH@iqn5 z?;ilML?RJ$9V671R4U!#Iz}WinM{JZTtN`2QmK@pu2N4Wa``NxQfX!ot#$^{Xmr~+ z;j$<c`Wac&>g^qjd;+Mrj*-t4Dy|b#6bd*+Pt%5pDQfi=wPQ3IcZn=8g&xp*CKE$u z(db|b<Nm(cf)j<-YNY{fGTBI?)*T!gAu*fn1hHE8Xuz0kHU~)#4k59a%}#=dX_Ugi zI2^7!a^yZjWSnBxZnt~>x-s`LGP5^kU>L>)TrA6;0C@jxeL01O+O=3LUn!5*>+|C; z#@J8_HgFbX0nh#I{QUU%`{~6GH;+r<4TZxIl0>5{V9$cV*q<pEKhYGs)9Lh5zHmIA zz=<Oo2tX1{CR2Cu-AEu33i+r=Je|(qWSk-!OQo{J#ynmhOyN&tGP$|`u@jb!WkEKd zFJy^N>4`)VekxZimGCKCihQ|TE)WE!sAQ;OwN|U+B$oVjnFob(`Km#XM7mNfQuSJ` z*2GEb@)F)(xVoAknM$=<f~3_V2ujfg?M9=~CJ0PX&rzLbv)P$@W7$Fh-rw$adlOUY zb$Ea0x<A0Da4EXO;jl-LdJCoK-`v~`aMFOJ3wl#Xvo#uBQ-i4lK0K9-M)2V&WSpYi z>rG_o^ihh=U@(|_V-NMe)o+jt(ePu5AK?H103~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfVJ3t* literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge.png b/web/pgadmin/misc/static/explain/img/ex_merge.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd8299fdcb72604d0c97816d38ee25ec51699ff GIT binary patch literal 1127 zcmV-t1ep7YP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001z zmC<Hv(ap~CyuIwd!0pk|^3&Aw$H?!;$neU_@!Q+=*4Opn;rFJf=Bcaa!NTsv#qYJY z>$$q@!^H2!#_)!zWKxY8p~PNwrpGpj!Eep(LA>Zn!0CI@?}XFvW5()e$n0**?3dZ` zpxg0;(e8}Y?vd5*uHf?tsp4J4>N2(Eb<ON+$LOQSVRDwC!H+ic@W}A&w(se*^X<m& z=CbYOvGMD~>g1j2;F{;$m*?A-?BlSe%w_81oao+}=Gm3(;;-o4nC97(<=2z!;H{?6 zXYAmv@aV$Fs&%W?Z0p~x>fEaD<-p_8kK@pe>DsAbl`meHCBewL<kgaJokg0;U3jiO zp0$U%?SbUekm1dYi>qviyiJ|ZV|uVayzqqY<iF|Ir|#mtzsI+$-f_6=fAHqO=+~#` z)}`&=yWz}=;K+#I$A{+Bq~67a=F_9#$%)>?h26u0=Fy_;-MZ$|qU_wb=Fy?$&!Owu zx7@#g+r59}&Y<1Fg5%7dI?;o_00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0v<_3K~zY`?bGX5(r_3DaGDn~EzQc+f-=ht?ef4F_ZT1uwF%R(Lb^=WWfKN0 zFq@$K>;1-ob697`-_$p~@OkmP`<&<Z{qD@+xE#k7!Wh%W5n^n7Vq%hTUY)u&O-wtT zGuH_$8NV?*J4f7{pT9LmOy0gTHS@oavu8O+V;7hOa^b9myh~n)+@p*!Z5*NQyWH*v z)WgL`OOL51%THIHQCQ;gcsy=ub#2Y{oLXL8e6fNj_O84fA+P%HH*FjNug~Z6f|sUg zKlm9Y5Ckmog+d`3=x{j9027HuW0vIgKO}AtmSrFiO(c>wNIZ@R!?LLW#1iZ2j3wDH zWf`OhpcKJmHj~4WH(-ouTamY;SNt@?_#qgJC3BGDIDQkbgke(=lwv)NQgHcvL9ilQ z8{6+3!+!vnR0I{9Os9(+@P&dk*?IrrBQj*kFsRrlDmGgz?(&F~%a-KR=PzHkNs=sy z$c&`egFQj0NLJ(<GT(ocN}?!|HXB1`XA4~s`&V+=4EGZ@c|njsl4WJz>dLS<v7aT= zPa%}c)e6WpRjr>w290sM`GP^JRT&hu(P*AR2H%Cx8^sD$O;e!W_|<CT$uNb2QXDjY zw-2$zW@Dx+l2DN)*ss@{2XOdD*N^ZIt7uwnm_qM#y2p4TYc*7Cv(-A$5$Se&c%rB( zDz@D^>F99WwM7OgbR)%4uh+w8IY(ocV>y2TWnrZACmaDB0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1n&OPyYY_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9aa51fce9d775f169f70d115761e9817541c48 GIT binary patch literal 1599 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_append.png b/web/pgadmin/misc/static/explain/img/ex_merge_append.png new file mode 100644 index 0000000000000000000000000000000000000000..12fc55d76f504140935d5fa422f9a5075431bbc3 GIT binary patch literal 980 zcmV;_11tQAP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005JP)t-s00000 z003rd(Nc{WHi*FosNxW-;$)T3a-%gGuH(UvHg>8zdY-9xu0FMyetNM%gs???v_por zNkF{mMZW2fwrozm=1joprKsemspnI|>RQ3)jlolwyLFkoc&e=DiMiWd#p`6n=&rBn zp~POI$6%JsU2)6oq{?G&&F-hoW_r%-+rEF>y@|ZN?A*VB+`xgozwN%i?cKqGgVF8X z!h^rT?cT(M!ou!_)bQTLg~G${i`4Gl$A*&C@5RRNy3wP>#_+D%ag^Bb;mnHS&yCB> z@#M{(<j$YW&GF^VpySbw<<Fqw(vQy1^0ec5<kOJl(V^tjk>=8)<kgbV(emchr03M6 zw3*OTYfrLEud)710S)b!}rrs&tF=Gv9%*r(Rk^ttPQ>Dj2~+?VOvsp{Fb*xB^D z?t<yus_NXT=--*^+qmiAn!NCY>)x#C;hXH;y6fMq?B2TS;+*W@t?c2h>g1i+<;(2i zukGQy?BlQO<FM`Hu;AeL?&7`e<gxDKzU}3)?&h-Z<-hOd!0+g@@9DJg=)v&l!td&~ z@9Vbl>cjBtw(#t?^6bU)?Z)%($Mo^Z1Vq=200001bW%=J06^y0W&i*H32;bRa{vGf z6951U69E94oEQKA0kKI$K~zY`?UPkg!$1^;v)KUULUEU1#ogWAouV!7?ykih{xC_% z08P8uzzo9+=i$EWd~@#Ev&%65`jNspQS#J=aPdC=LHS%|Vph=rrxEdXaCDB~V*P?6 zOSoTiagtKVQ(H*3K0T*!kezPn9y(&R*|RBuD5{jL$;c}oWwnJQBj0x+hE!(ZG4|b2 z56J|uqU6ai*kJH@XNdN;E;@msASoyeeLdlI2K-Hg!O>Vfiyb6RLfk-<JSpwt1POuH z$A{Y&cse`Wy#}=#6BO#@!i&hmHd?uav*Et3WuQFNGM5Uyz`)%Gnzz7yUq|yS4PkhF ztFRheEux77*lcU89;dqKTir#MXUoaK4P4Akj_d*D?}vtngvyQCK3LpK>BaV2;4y5! zFcp^>3gRlIkf(HCo=X%&Q8JG`mtuU?vnWc&GXk+=|5<z>)+K-bO1R(MTt0_mbAQjO zbuYw{VGA{*NiY=`WVb62QpvD}s*xFtx!GwA)=08cuRN`gIaG!Ep))fzsaD}aS{Y79 zOvZIsXsWB7QXr(2iS{Zh6GdK`j1X5QioEi_{zPxhzn!H%4w>%&0000<MNUMnLSTYP CgEgxF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce4839e02fd3f17b5fd8e358ff204046c38d26f GIT binary patch literal 1344 zcmY+CSx{347==TqEn;1Yb)kzRwvO5s8xTS1=pdpEBQS_s6{;)(R?#BJSj4Jq3RJBX zQDkYPh!_@AR0IrxkdTEC5=cT4vWF~}EH}AX?oB|$Ort*a;rwUL%=w=FQ<a$T<6{5M z{81>>;#h1<lGj7u%Fow(H%%9op-|{MiE#(_c;jQdE<1-e#<7zI!9lWxOtDPx9D+$F za|9Y;+1PBmM2g7e2w&iwoP>oUczW7R8US1I0KR>uy>o^_wbJQO_e)bxulW@b<ZvB4 zo@1B>(HS=8h)pa;>PUr2w*vp69j|&N3$LV{>k!lrt7&peF2@=_WK3t6FL1zCrK1;c zH7nuAD!5GzQ;lwx*-Zivior!Ux<t@i6v-ISq51BG4od>61lETNxJ+QH5ZZ2v>;w(c zr$;)~&Sx6uh{@f|NG-y(<=?}pne`Kl{^u_ZM7rq_Go5lf9JaG;VDH?l&W*_Qz^qE` z(rDcPFl)8GZeeAZfrp4=T%kmSLZ?ImE0ivyaqclYvz3#LAOEF|e_A$BCFnXQ9V7Dv z_73408`uMxdz=u{jY#L*+Na`NlkRVmw$Z4rw*oI<I~TTdU}((ckeqDT`iPf(toCb@ zT??6djMEJURo#rD7SwjRVJU3mIH578m5tcNm+*=8qsIyfJBhqUufSr+@WP;cFeAGU zOx1wur*5ajX&H5xSqLO*8Y-zE#x-)&i@KtYKUhz+mi9wsb~6oB6U@p^NJpMUrV*>q zZCA}es>*=`951s&nb&8&N(4(twsIRVWR$lXrFet*iAB}#cBo*>Bn%3iW`PS*7^Q7$ z_8+Q|3MKs-z-xxVNk~tFw8K^n)nS-0h+9>R>&oGB1*KF!-sCj%Aq~|!O|hzn95ds< zWQ&4YCLb!14P4c6a1JBSs-{>}Ll!034sgw~K0UWdJBBk&^&l3R0~ojKxv*KPW#gp8 z%b<J^8ZM=HN9j|LlyCqQ1x#go!@_geqvySjeW$&woSohR5F4}WAeMO|ZS{hWZ^o@H zjt<~cX=Bt;2A4)*(K*93HuL+nBQc3L{_3j4ufE$?-cl2G_hx4!iJHcXCZ>+~h4>dY zSFdYJuBo}Vk>A|xk3MZ$+vF3p@YH_cBwxfkBosto!jdAwL$+=?ya7+A@<*k6g(9w! zvR@G^meB8Yt<;>!+s)T3aowoc;8%FDtaxd7@E|tX<MBnKJ@e?Y(o*z}vfa_c)PZNG zs-i>z%K`%f)vG>Tv0{ZT@XO_&ueyC`AKI845G$^ZA*NQ}>28@ViTY+6jXxB0|Ihe+ zAGQbA9hF3-<mczxr>ZM7wVqPyI&zbynjb2^vgu!ZXGXE!his~s5{t;!8Lhxdd2+H$ z`a^M1P2{d350QAO=#A%f!-lxV@)Wji(}5@Phm(@(Lzd&2xj)T=+t1GfFXQUTsNU3- z3CFt&S^TUm*_%@dF`1P<NcVl;vpy!2^m&H9U6|t$5mLzMU;Ubr=F|HHSR3Eadqx5D zUS@KS_2<1=;NKL~a}pYy|H!jsP2}&ojk|&;3b$YI&{zkqJQ;7?@f+?)@T$!?Vu1u2 z6*|R)<?x~pmIY>P?D=^xPs_+6o5h4r&fZYnYKX{H+WIe;MNe~RudnS)#<~{;28H`~ zp;7y0eV6*_*%98?uP@khq#!fBAS?1jewNozp_mX%a7bt{Cgfl!CNgYGWLVg@n5~f* t%(lAqYyJnE&CNWOeepej+5QfA+m6J9zXwKZ4|RG0RP3IF7(#Sf>3<opDS-e0 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested.png b/web/pgadmin/misc/static/explain/img/ex_nested.png new file mode 100644 index 0000000000000000000000000000000000000000..15c47316d5d4163d97b95cda99b2e3a2049341c5 GIT binary patch literal 1108 zcmV-a1grarP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002N z!qAqP(SL){b9d2ZYtf>m<h8fzyT0th#P7ht?ZCnA!NTss!|uez@5RRN#>el+$nVI> z@W{&W%FFS~%<;_4^3Bfj&d%}9&+^dF^3v1u)YS9U)%4fb^{cMtuCeH+s^-7I?YX<_ zv9sxtmEUxE)|i{&!NTpPsL;d2(7e9v+1d5IzwF1wx2vUWos>nDi!Y6V8N<SK)!C8X z=A7p9r{wXW<M5#4@SfuCp5pDD;q08@?3>`~o8Rb}-shO$=$_f!mC@3Tzr1kL*o)26 zebU;8+TxSc+KR}^cFoU%&Cc<&uw0mqEU~Ov&d-F$$aBxniISDkwXlcC#=6<xjNRgy z+TW7e-jUhekLvTc$jR@iqGZ|JkFBog*xQf2zwOuBjJLS!xVh`s*o@`wtmEsW*yMoL z*Nf}&z3K0|)z^yM=aJRciPhDL-sP6m)QFdjE7;qU%*}nTs8!L=iO9rx!oF?G$b{0> zhS%DTytZrH;g{Fej@H)nL!K(600001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0t-n*K~zY`?bYj3+CUHha0E^Sm0C-!f`UTD2bF{cA89RMMd}k-_8X`@6D zMDcCwzpmmq!zFho^0nPBncU28_IB=WSEKnK57DI6=@B#ZI&Bj!nhh;RQ)^pWyU}cZ z)A6?RoyGFL>qB>s)oQibdVBlq-DU@7w9Wkk{RS54bh=CqZ4J>G20jkDS^IJi4ZF;` z8lrbO21iC&#g2{)nR@g!3&`nlGsS~(TRx#$;_)EO3xVtkGWPWA<#-<`!pC#oDzTG@ zm-7e4Cnl!^LHPV-`fD&4425UD%|;##g>e44==XU{gcqWVOA$^@mY1u)d>}fv62tcu zi?6P&^D2@+DDn7(31MX;iI<(+h;RM?6?qPr6k<u`VluY5#Uwyj-DZ&~GD!iwmYp3E zNvTN!?e11h8X!#~86`=e_H5Spl!p|M$tel4d9vA`ebie9IZ>Sj{rZg<Sws=27lu-c zC{alo_Vx${Bq~Y6em=jiHXz9~0tdl-K6I!$8ITL~EO2y0s0Io}dif9vlTN=_Vvz7L ziImF>GJZ_B{3m6ZPJE}8xcZ5m`Oke+!p|<Q#uX3w<m}?|il?`W$kJNndTTqC$=!&O zB+G?jsp7x9xaAm4DY72;gNf4L^Q&7%Q+ieFtE0i*;iR56euwqsx`u@l8x{?Wqy`3G z1LL)UA^xw%J#C$lG-cRqEC2uiC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$c zGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLe aHY+eSIxsNGmsP9)0000<MNUMnLSTY)!c1@g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c0763337617f9ffe8cf13ba0f47f4cbc228c5e GIT binary patch literal 1741 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e8a17d409343ea937e43ebb76e8ebce3cbee49 GIT binary patch literal 1679 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 ZD=;-WFfhuORjdF2002ovPDHLkV1g+E(G&mx literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_recursive_union.png b/web/pgadmin/misc/static/explain/img/ex_recursive_union.png new file mode 100644 index 0000000000000000000000000000000000000000..66952ea454e3703dcb08251bd2273193aacaeb28 GIT binary patch literal 1224 zcmV;(1ULJMP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005?P)t-s0001q zx!X2~!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_`zG-s;qsyLGzJqh@Q-%+2w=zwN)l?ZU(F)710W+4RoO^3l=q z)YSCg;P-*9LUN@xnY?(sz3iu{=c=sduCM9E#_!9_@xH(9!ou#w#_-nG^mC;*r_X10 zsycS7JFwk!QjHmRt30ycc6zZujKETQu|cJ%<dC*(*yYQi#9oB3MRKDxqQ_vQ%44U^ zW`?#&cB(tB+HrWUKD6U`wV8gwk2a0LQ}pr4@a(tn?6&Xfw)5}D^6bU!<+1JKu<YWm z@aVy|=X~nqo$BM9>EWC2=(Fb9mF3ry<kgbv-mJOnfA8zI>f)T}-<j^_vh3rp<kXSl z(vRufs(PNOy6%GS>9pzKn&{q{=iHa<<FM@Dt>n{?<I#@d&yDHXsC=|Tyzqqc?Z)lo zvGC}^@8-bj+^Xr?sp;6K?cuzZ%w5~PiSg>g@8!Sl;=SnCr{~qB=G3I@-MZ}IuH@B` z;?R!h*QVdchTg@6-NJ+A(V^?#t>e*;;mwQZ)TG|TgxtV^<<6ku&Wz#Air~qK=F+3x z!Ghesf!n@+<jtP$<G$?Py6fAx<<Fqx&Y$Ypwpcc+1poj50d!JMQvg8b*k%9#010qN zS#tmY07w7;07w8v$!k6U00Ih0L_t(Y$75g^1>^xnCJ=y<#A#t-W?^MxXX4=G;^tu@ zQVTC1zknc<kg$lT7_nMNw?!Q63n)p*ixQGjKvG&pR!&|)T2V<^MOB)R<&tXZ8bB?Y zTG~3g(t7#^hDOL*uzFF-*u+!=rxxs9)G#x*z@-Jd7o{w%tTk}?1-r1MjV;hGcG4gK zB^fj<EbJY?TCiG<EyOGw9i6~>aJZKN(>M(aXP_REv;f1z+0g=bbYa!PVBrGNg6c&y zE$GHsxMJD@@iq)#7-!*Tfnhl$q2L6P?j9KF2$E260x1tqFN|~qPAIs6hL^VmnqMFZ z1!u;P^700z3Ljq(fRfOJf-}iV`hlc<{R0Anf_+0m!@?tc(LxL(V^~CjT<see6&(}n z8yXj%km!r%atvE6lE7M$Q({uneADAIGPBUNWP^PHCBa&9z*=(i@(T)mi;7E1%h0u; zIvN;W<rQEpm1$Ll)xI^gb@dGhEf7DUI$Fb`yrL15lAFL`1tk&D3{C~8j<(1F>Hy^z z-{$b5#1`Myw)T!rge{O%fa+*?uJrBd&g`l4?d|KIFcHZw;8cL!(G0$mCYMfW^PM_v z!t@zPwt!Osc1JV#*3O(YyWMxr+<EgCAhbYI0d_|-_%5vPow~?(@sgzrmSKb#c1Po| z9FL>%0_={)uLY~4@dA8~9tHFV07F>Y9b_N@c>n+aC3HntbYx+4WjbSWWnpw>05UK! zFfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GK mIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTYtrHx7e literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_result.png b/web/pgadmin/misc/static/explain/img/ex_result.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd7b5904f9b304709ac6aab37e24dcc06d233c7 GIT binary patch literal 1320 zcmV+@1=sqCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002L z$<UU#(67SKeXh~4!_bAX(Osq0Zn@x(wb8-K&}gpOjmqed%IIXO*vQS$YP8;l)bMe> z<bu!aVX4@+#?YR;&}^sCf579B&FEmJ)}GYufxh8%tI?>y&|Rq4YRc_yz2s%c>~px_ zSfSIA(d>o8<yxZCm(uK6qSJ1{=25}wjkVEryyK13?q#joj?L+~#?YVI@LHwSTcFW` z#^!Uh-Idtykjm$8yW%;y=Uv3<cDmqo&Fy`{<dN0xWTeqv!RRu#=5@;IZp-X#u-cN- z?P09iK)mRBz~p+$>VwejipJ$*z2zga<UG3PRl(?g&g_)c?q;&xVZi4cujDnj=ViCx zTEpph#prd#=v=(zEVboDyXJq$=zz%RWX9`=(d|CD<!s68Q=QRq$?2xQ&}6XOaJJrj zx!-lf=SjZld&TESz2|<->y*ywR-w~O!0LI->S@2`Yq#KKzve-^=xegvb++DV$m?jj z<BZ7Wg3arCyWyqU@K3knEo+Lw00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0^dnQK~zY`?N#Yh+CUT!A%sLMsaGh-LM_OZl!8#apdwKLmBRyy7FwkURz=05 z^{DN?-f#qVLv*HJI{o0AVTQN6zxUqnUBR$t`S+s2aTTPh2@R$Ze@_Uhr6?^eX#=!w zkidu+dYpM2@p6b79vK~LYpmgw(Ik4&kDGzz5roD1dV(B&W5e4B`=q1wly#1~+^jML zcsL#Z*85J~R5W&<&+Tu6-BT{7A|X|P;{qx^*y6$v?}zk~X*x7LLn!g#XXoaFl0t_g zAIP46<ARx1fJ7H#9?<#k*9uEIb&ut;cg5uICm&DDQMi=5<os$BHaEGpPRal*X-K6r zalBmum3AqcgrAV>8=EE-ir5<7j^*+nDazi&@X2h!2ImzwkBpdc1Oj$;KNWK&&*v{K zHc_Fp2T>6_XL(<6MG=Sv0DC5#0-#mAvC+Nq*9v^kIK2l8vdFM%Et8knvxnJo1c6|c z&4c}KvKHW}Vy0H@L~i3sM*z8wP6~1|m|;789O!rkC-wRX3IT({=^1*&oHufd5<hTM z>Vx<$E{y1rNF{wq{1pVhD#p6C2Rn5oh%7L0oleB1N|4Fp`jMQ=#pw)z990@QuA5do z%zYPv$i2ZQ&zL%%$z6BtR(}-AOZ|1ZsiIV3#aX_aKKpI?Rtwj<S$$bw@^{6#TF;1K zr{3RVX9kpAD%Y_0MwLA*6vA-iVkfW3ieG7@w;>~pUC1Wk{1EpWn@(i<$E=y+6>NkK z&qpAySa4-uHvH^XzT03OH><a{o{ehAyMj8w$h-WttQ&NZpV96kV4My?L0ABbMGMDq z*$yScYY)=&)1fH`v<WoU-7VJ2U7}9J&`8I$z8yYm`gKnZK)LWFQpDw+wQo`T$%m=d zzQj%A4ia8s<V50kDpFI}g$%88-LN9{Um<<~F?K%Tp#n<Vv$^~qaIuPR*#L_H0A7VD z3nOkq=7|r|v-~&m2P92<JOAsn6#xJLC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@u zGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL< eG&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTXtOrt>n literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_scan.png b/web/pgadmin/misc/static/explain/img/ex_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..396dfb4feabdd85e081bf8336304129058633c5c GIT binary patch literal 1320 zcmY+CX;4!K6or#E43U(&OiX7G0Tmtd5DXYmgR&F@acWZxiv&wwL>3hgrBoq~lr@it zLJ^duAZWq5fw&ZkC=h`X77>I3W&snjFJvdI(x|^WbI&<*@7(X#z04qTpskIa4Gade zJw!T4v82aGA-}XZR*;$vgTXU`4u=peEwhE|na4_cJ>&OMPHdC^GN?%#(geLygmo&i zN3_g;wJ~hf>0VV*pQ>a+SI*I098_lwt84kXyOa8Y(V1&wnnwbI)t>@VyL>~#^s#Q` z-ez%7n>4gTN@YnI!|M1RSrS`*eOyDod9RKoioG$+D)iJTAoVnDW}2o~Kn4Y*nFci? z(4d5jN=PdLbt2HDg!CeCRtX6-W+}%-_OSp37f^A587`pV0tPWSt}w|tfRYQSEfXG~ z<pD-9I3_n5EVvjnE1@|h#C^#el^bWp;E2qi;{kdeVBi5}F*q#M8+pK-7&KX20?sR; z1r;<X(GQCC^Ad1T#TXFlOnku12j=+L1qs+M(#`ULMG4q9t)1s%*%ntpODaaswDupN zW=R4rs~Ft^&Eh0>X%f3E0nHYQkNqG4U%j7Mp2U7oF*>GZTDYnYlh_prI4U=^O{(k1 z<RH8(z;Xk43WXdD^Oa1*TAEd7Nz|V$N&2LK-gs{q?2D;G2mL}wJ?au}Fvk}SCEl-Z zn!Q~=7IE=$y}e(yGh*kDXdI~~U{jVK(F*Yxuqnx~>1&_l=Y&sWTE`Nqyi*-+eA9Md zK3zI6YurED-VlgxD2VgQq4T)o<{Uc52dBM4_ns4qT@<Dvt#*S#&6df$?z_JA^7Nd& zsc>|3T=BIfA3pq|mf@Ygu#{_8Ub(bzb>X|nwg*!@UBbMkgoVpZr*Tf=$$yMQS7cHv zJl|yI9uG%_?<;ufhl(nz-b3s9yRngm7!eBB**@c+iOV>**WUgtxir4qH!Q58sBY^X z+t^lqCrqiOuN6j!FCm^Z-Pw}A4cEdyv#acY!)jFJxKh;d#_(duq1<!#u|_inUhRb7 zZuWs4?RmPM3Lb48C_72VNCv(-0Y~+p3u~M&y#z-hvq<OPO#~HPL|HeT-JBnDa|-Q? z%<Wv4nUHu7scz!F?nr$`t8(+1oBKW|Pe5|!z>mbS2==EN8$unCzu)=|NpXJS+8k(y zsf-o0Hs=vz(jedS7h1^)Nk6Egj#I}j#|fGRi^DszZaa6=0t<S~OgC$5;PxXZf91sE zOWU(6NzTED<doV?9Qs3{X(;P@)9MkAuHxQkhHpV(D8foPn!Wy&AP<pDsLJyP%3oh& z_cAYs?`!v|IYy!w<2r@-;@--2?03|0W>xir$OP}|H5oNdm)-MvQ!!rm(9c)!#r=_M zBHea|)}|e>!%!27`lYDuS>)H4O$vGq?bkY|V%O_yDBIEKFR-P%ozXV=^u|^833oyO zaZUL45Q3B6k&=}B<!$*W;*kcVXyLiC3y+ARgakaz>j~!U7+UU*(%Cey-DHB+7FHqH zPj|}S-*ndrRToh|R<X8I9r-f-LcEN{x??i2OZ4-b(JqNaSpSxvc22t`6N*Rz>U)~O z3XiIz)B{0V)^^ow^e^-{bxVdh`d7qN(nH;q3&j)u%b;lk?cGMHsP*lX<>$Ai5W`cV zkEg^CP9(=z0_K5p$GN(DxZ>PHJa7d3E&?9!g4<2N;r5nqb@(5Um=t{~HtjQj+xH3h axJ|%$eg^tVLmyfI*dZeMV8gextp5Q0yRj$$ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_seek.png b/web/pgadmin/misc/static/explain/img/ex_seek.png new file mode 100644 index 0000000000000000000000000000000000000000..130fbd8f53ff5c2c757c8173eb62a1b604555f34 GIT binary patch literal 1326 zcmV+}1=0G6P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=yH~!hN)yyjTym@HuUhw@a(tm>$dan$M5O1^6ka$=CkqY#O&j+ zp~PP6<(}%}obT$j>EN30=(FhFndjV>?d7rN*p%$xt?c5j<kgbw;jZi7t?lNr@aV$t z=D^3Qb@1lE>fEaD<G$n4kK)jc>Dj2{(~#oMjN#0S=-8+2;k;g#B*DnK#F|j0%w%+@ zIG(kKuGw+%>WA&)VD95x^XP-`;92wMfbif}@ZVJQ=6#RAQ?cH30002z+A8STDCyWG z>eeFb)Es@XL#xzmv*LH^)gSEB81mgwaGgbAl`r+=dg#}t=hUR^+_~n_qTtDi-^YgD z#D(V5q}{`W+`xk0$cWs(faK1gsoHLy(PX^vg!0`^^V>}K<977gNQ<j%pw(yY&=l^^ z5bw?o^V&-A%?rQBx1!f+zBxuV00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0_90WK~zY`?b6v(+E5e+U>k6&Tea1i1BihN$R<*($RcX1MKFRGK$JxVf+$KW zhy}F%>%F-wiB95-Go4N!ybt#&-#z)Ab9#DS&%Zx!2<}MUVuX;%<?>#luYX`*kQjU` zlMN9=eZ#{e#K`E_*gHa$$j8UW<wXC)#Ke2z!{p?ojOaytm>8X!l8q66sme$E&ysih zt7&qYC!kO&l?v`wDPTseR?osLMNt~iXti1mw7()hkpiNeo10UDQm51DL2WP?=7BPr zOlHtpEEel?M1_c&BSs1+lgXro1&hV@3{im|lX;^N5wpo;(ZZt5X0wYEg;J%O;ZuCZ zDHa^yu-ffQqT~y3NAec0qSvcYm3fLnRm^78CC#GM>VRdZ)43x4V<?4zPhsh%aJt-X zk2q25T8%Zf8@mWro6YM4r`x?MMbIodjcv`s?sd5kS@roO$Sh8w!6_Vq6e}Lj+B#1* zzIONK8}5wc-65M>-;p8xoPq5?Ah6xNgTWoxp=o*tc0-}?Ubo6-WNU*YN&h}F5MZKA z00PlyGyuU^EFJ{<;NXCUP$H2C^W-qHdF1!+CzB*1Q6`E>EC|7PJWeB$N`)YtNT)MA zA&*Z`6(sm7u~>_s_vus$y&p~s$r0`tnG|LTK25Qg$z)ESkQa5#FPw|RYPB!JQhOF_ z*>zaY<#Kt*vn-njQ6gLqkFQY3Lhh_sJO}ooRAReiUr6j;FJ6yTv>w?);W7ugV)23n zwp6+*OAwdK?L_bUd~1-sJUh$5dGP|1D*;IgiByVwxm@mMIr;J89XtMch<EH7&xM=C zF6@TGtyxq~;j~(<-oQ<*R=ep`xsCif<aX?uGe9#bCe)sFre3dCpxS6Q@1S;ne_!j6 z-?x#6<TXBM$LJK(U5`q=-l)P|v)QaYCdl9&YgGv`2__7gbiIy9qk#$c@nh0%Tq{c_ zMWvPEu9M<XmiBo`$6n9>cm4nf0rwvzb1L2d001R)MObuXVRU6WV{&C-bY%cCFflMK zF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGP kFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f_kQ{fB*mh literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_setop.png b/web/pgadmin/misc/static/explain/img/ex_setop.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a9b1983b5b47c96ae910e73ab4260ae9c28b73 GIT binary patch literal 1143 zcmV--1c>{IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002E zxzL`V(1?rCc6!ljZ_&-ct;w>B#-wM%nNGrzJd>5te}mbYo#C;w>b<`0$jI=)!tS)S z>Yk$FfrZ(}s&>qySJ}LM<k6by-Kg#6v*XQ`qNLELspq@A?YOz?x47%Bu<78)j_l>D z>*J&8;hW6M%aoVjwzuoBvgxw3>bkq^zQOKonbT;Cw%F6E=-!y;+?VRzrRLP5*SC1B zujqQE*JQ2NWs|?=+Lq|snys$rs;uaQsoGkq)?dWwX2$7un78KHmFC!#<=2zt){@q> zb)U22NtVh}z2-Hy=1RThb;#&boz14Or{vX=<kXSo)|jNH<fy9WTeRLOv*bFs<#o5* zUyi-x(~#rRkKMwEAh6_t&FbUOj<dAt7_H;t&Wz#Ai>j^WVVTb!u;hfp;!=vh;meBO z#*ekO>Wt0lK!(EL%8BLApgM`e53A#l)9m2Mh~LPG-^YjE#f9R_n%=~P-olRE!h_qr zgxtV_;K!5Guy4}DpWelaCqTqQ00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0xn5JK~zY`?bK^i+CUTrVD7hwTp9u~3K&4efQ155Dpjm4f~c)k&`L{%-n1>) z8Vm%m{&hD%k|mfKr!(y*&NpUw=DfQ(dlZUEP3k|EQl-{twHmcbIry#98;mBC(V*AK z0c6TNZLwNy_D3iJkj{ZQUHHrlPB<~gy=WGlv$#E8ug7AuTIbPOJx2O`et#ek@cVEQ z(~p4#WO2zm9bC3Ac_=qPq43IMANT)2Boc{6p2Xsg1qngSR4_5mlTc_inS9EFXf&02 zhC3aSREyMFdQBwH*EcfBO%4E&da?EL)fS!|$)-f@i8MsEbNQXZ?%w{O1t(s=IdEa{ z9UyO)4`C8M+9{SY$0rd1ygNNTC_~YdQ=T+TwsVE|#Zvym-aY_BQK?j7P#cx`;~Y#@ z*NbPxQepRaGbMm(wdRV8r%``OjF8VqUpSKa`fZqr1GRJF!XOaM_w)$K<<I)$$4{|E z?Yv%V7zLtrAHsyXEd1ig#_vn9Mg5AVV<tJ`7D*pe`=HruLPQdb$`$xve5NY^u4%^j zfaCL-0Jv_EZNmdDS!~f_Sppgv`A=CNwrBy-V&I993`~e0m^z<{1x0q?S(Y2i<{%R% zy5-);Sjr4PEwt!%S>{IaFeOjS2A<dne{2A{WhN_mVq*{45?=X3(8Ek!_M&$)_K+p( zBEhYTPJ<wC!A;%vn9e=xqQ8_-b8vJi#oJ7y!L+k7OG)t;t8Y@1`X_Y<dEniZp!V7a z0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFU zC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ov JPDHLkV1j^qN`L?W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_sort.png b/web/pgadmin/misc/static/explain/img/ex_sort.png new file mode 100644 index 0000000000000000000000000000000000000000..1d46fd34beee098f997529bf0b7714c52232a2df GIT binary patch literal 1157 zcmY+Ce>l?#9LKkGD0JGb!<|bOQ+Me`PIBs@X131ubm*x$mvXaab;*yACb5J^<yUCU z=?G6fnfz!u<i}*hkYy7xW3|nXjiOR_@wspHSATpy@8|t_KCjR7c|Ol4eIL!oZ1p#* zQ7Dudg-rBA)cHdg8z6b}L>w1|LZ92`8{m!DQ{|nmX`=An**#5DzO7UKZPUMtXP6Il z5fWW|pN=clXUJv+$_1mFs&#^Aj(62w4Qg7mCQzhhh$nO8bCLPQz+!<`3u9yCLG%bb z?15U4$&kq)mBQ#~6BITAuO9LqLIsSB)IkpP_6i{rRI10&2s?LDwdh7Z8fJ@NCJm;! zFd4t3ITfD?Q+k-tfKm+#6{x2Ho*jVkUqDF&&9OlR$ex0982Sc5B7<QifWi&bjP3!r zaEsx0$?8cB`nK#iITTstVily{c^X+e5er>i<q%g4k%ho6fRJ1W5&*YE99$-0RE<W} zX*u<}b08K&QxnwJgHU)0{BOZo5Q%sYYAS}-7f?P0MUzmdg?qD*qJqS6;3y$x4DvM) zseqCx$W=qd3>dXTM?bXpLR$}rBv8e3)XBr99y8x4qpF)h&;TP34lIsGOB-m{TFz%8 zmqJJT(fm=Knjt1)R-Gi%qYx#33{uyzT`1HF4+_yMfZVAcm^py)vTU8m)18%`sKnhj z*<uksYUi1eVOfJKPs>_|AHuUzvW>}&>XtFnD#12=5jSD-l}O2Xy6AEAsv_w~<-a~= zR<a9*e9KC+;FgGmLH*CMbBgT*1FGqRFG(blkIk<5_s=(bzrrV0ONLT{JvvNXj&wR) z>7XZDI#BoKl9GL|_MWroq;CqTDQRU3U&c7L*{b^OT#I7a=4*Z|__`WB7ft(h<#lmL zwVU<juuHW=)EJqm7n3feC-+#%HCxw=uD|m{yYOyl`E(|KL();vVdHgcQY}`jeA$Kz zd^GU|aTDfZM~Hc9Sy{U?g_H0ClY?C)4vFx^B<8H|$3?8%P+fzuPdEAthoRteGj^qv zp2y-%Cb5#6EEi(d{<;x1@Ul9Xj(^`H-CwfeY>d+eFuzNvy3((g8#?Rm4)+uXRZ{0S zek&Lj2&|vqTX>h8z4p+Yu5=*Wb*%X-%fX;6ZCeB97F{VJdvHeYIL!geO(qzY#fd~4 zgP|L%u1gYzNTmVY-#^*ix*}V#)w7h0IfJh~v<cg-uAtgBZSQdJ-+WSx^D$TOOB4TV z&ougHZ<*gtEH4SK60NlsIlMIuW@DxNaj!)u>tp7<>2HN#d3gq@q^0Jug@L!_)33u3 zSD40j=<&?;yenlDmRu9KMFjKSyr<uxY0vOCm{D>(4e9y6VRvwCmgKfwx9qwK@bjUR zis9q0OCHVF-XIovFSc|R*2(*Lx0j!tMXN^#U$e&f2a$)ekM=$o%{USr>i$P$C?Y6l zf)l~f$=Q+M6yQv7ciHCd;_?IGCwBtDjc339GvLo~Mi}$-CxEcyBk-Zyo#6Tj=q}h_ PfdD9qH;q`i`*8CAb@5|F literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_subplan.png b/web/pgadmin/misc/static/explain/img/ex_subplan.png new file mode 100644 index 0000000000000000000000000000000000000000..e13d7794e91fc0842702b0b34c1a9b61607dcf92 GIT binary patch literal 1283 zcmV+e1^oJnP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002O z!_bzQ(SL){ba>NdYtf>m<hHo#y}#_l#qYwz?#9UP$jI=?%J9p~@y*Wi&(QMG(el&N z^Viq)tgh&<vFNF*=D4}*zQ66j!R@lN>5`V;n496cyz8c@(AnDc$Hlj+rEHy)MVE~( zje!}GmC?n;b=BCB+u@bv?y2JJpyBGA(b0>*y>Y_8Zq(O`&Cz|**oW5HjmgV)&CP_q zyl}CsSnBe)wXlcC#=6+uj;W$#*yDlM;eY7uxXQ|X(bI*zwrqx}WKxY8b*9HQh{34O zXl={vL%r!uzvx%P>V?$sl-Tfk&g_TN?ycYR5Ub*n)$gj(YI2sLtk-VAk2du2$?)v9 z@9DJj?Z)lovFzcl@ae+p;+*H(mgLov>)x!v$huvZB(B<V=--*+(T?ies-Crnc&$CS z>3-?jshY`Moz7yq?t<^;!0Fhh?&7_NyG?JLL&vIhi>qwE$G7O#rsmV5>)g5C#f9C% zgW=4J+`xh5&Y;`Af8@=c4PV1400001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0=h{=K~zY`&6Md=+CUh_IT8h`QXz`eqXw2kLy;n)g4XJmdbG8avTB3Kp(v<$ z)p}e1_3p-?5Zu7nnNFV%o0)f?-@M1}Mx*)X((3dKs}!TxX;p}pR)f)GG8$jBwRd!w z%`ZDUEmpIMqcggeuI?_I0%_~9**P5z(YJQL>Qz?8^x17DJq=;{x!wU~4cdV|%WIZ~ zu$^Xx5QDtK35c8yeo&)jELJMwVp*3&xINyX;bB4W`rcrMwbBt;yniI{)+-1?FfbY# z<5dwki^CHb36sj4;gCDzP(xg7TRUOE_;`3?5(g$H!Vxb}L0qhf<BXVz0ua3qO*$hH zHH5VoIL=<X3)B(ZiOt5=WWh)fsJ71<dhlKp3=LHn5NrmCg5jxYL1vmmz_>6q?R^LC z+aGBz3y6${r7U>JZlAM>UNjEhXh=TF8Nd2bRuFzH;GTIO2?j%Mzk8N%fEdW$AV22w zL@?s<g=QOEOV-}=<mI>0-wW-D+06_Mp*`e&BlRIa<9G3lpVBjaeSfJrI7i?75F?V; zhba6A>5ka^!s61W*yk_H%U@$pB6W_~LOdQ{ip?)B&3~&x5><%OLCKO($?{#QQC=UB z<Ren&Kr5@OYb)r7D5loYlSrKdt)|oIH6(6iGFem^Z!W)?&s9dPbVz|M5s8^hVH*(_ zo>gwAm@Mw(G_XV%g#!oHwzf7zl+6?hyND182=m3g{rzGd!crMCwGM*d8pU;Vu)TYD zgz$MJ63OJ|-to!teyLO{m&;J$!1{@Z<P~R0Bq4++r@u~5@V88|)H+C(^;9Z*fR4`2 z&M%~1s%8btQZKa*97stu9$sEvoj**h=5i_>8k8**uFuf<<<-sY<GEC;&VjbCuSwwQ z=Jy>1Q997kA*u1=_V(_Af+!tz^Qco}$N!-}nbr1E9_U2o0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1oA>oooOA literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_tid_scan.png b/web/pgadmin/misc/static/explain/img/ex_tid_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6063a1af031c626802911fdca598983aff7d52 GIT binary patch literal 1074 zcmV-21kL-2P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002d z;PI2T-@Mf8{{H{L*6o?Q;ibal>hbyT^!nN5^vBrl+3WSI#^#K%-OAhV<Lvi^t=n~> z)~3be%jEIR<?+4P?Qx#e)#LN7$>)Ek+0f?l*6Q@d;qbxV@5$rvYnjrc!{ox+?t7-# zwb1FX%;=%P<Hg|a#oq4t`u(HD<awmm>Ezqh$F9h;kiMjKx|(3PkxRstJB*5mfq{XC zhlh@ij+T~|prD|vtgO7eyv@zc+}zyo@bKZ`;laPVtDlO=oI}p1PuR6w-oa?$%4zD; zYVFo~;L^J5>E!0-=GocV($dn%$jHFJz_hfqs;a7)nVF-bqn?|W>)wU&>3;X;Y4PG! z_2EYK-Z;soXy4!8*4Eb0(9p`t%EiUS?d|R1)xgxbiOHZ?)2mYZ=33Can9k15#>U3O z!^66|x{;BQ>gwv<&a=<QxxT)>xVX5tx3}Kg*UYkn%e$bxy}jh*<eZ$G=;-L1o13t( zu%DlwudlDArKN?1g_M+(;^{T(00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0qIFZK~zY`?UY$l+E5sVm1q!Z0s&d05EXH$OJzw&f>9JvV-~<xtzpr&mJ)3# zt^4}dJ;CwH5a3Q{crP>OnfJ;0@};Mzn|G656V%rsV(N#@1DyaC>j%>yg4)_VZtpi^ z4$R~na=AT7>*IZ1AL@sFZhUwc9|;5piB`Y>L|~&3j^krablejP42`#Fv4k9O$mI$; zF%N;*>=WT2Y&Irr9@rh6L@)yJTD0r+VpD$OYqp`G5qH=Twobo1f&7qh2|N*)`RMCt z5>^5=+dBb3rrVuclg!S|FML{Dj6`FxSe&F1G{YvB49;`QE2-7B^m-<<5!u}0xots| z<ZO=2OPoHy%R7<P^ye?Td;4GaGY3ktP$(AJk|>G{P073tp-|<+t)p+>BR|ra<Kx}6 zp9P^(`c;(}RaK?3e4@NYvh3lhmf7D8Y$NrD70Xgh{acr1xh^r;=Ey0}bN}Z4ADn5# z`7_Z35rLQn@fV!3T@cu3sYXRZOw?(q(U+=l1rYG!LIqTS4wb1%)v`)c*EjlN#riFI zORLpVMG%CdCdSn7?sHM{I%^=7WY6#Nxs&Jv80AAeN<QWi_cvX!_a&yZ5Yzei!HOA( z>8=<EC*^g;nl5r9OG%cY6BHS5^LNqB+sG4UmhG=%BJ%?P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$g8msoqyPW_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unique.png b/web/pgadmin/misc/static/explain/img/ex_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..cb70480be8a4f49369d9a974ce9461284d1a4654 GIT binary patch literal 1238 zcmV;{1S$K8P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002Z z#KgUKcgI3Ps~Q@~u&}o&Ddc5l(9X`ss&&DSHnvqK%tl7dN=mayB!;PEQjHmZrCYPX zru6a2@a(tm>b0~uF5<tRp~YT>vPSFWp6cS9>EWB(wt%)SEA8a5a-%iq-I&LARP5lb z-DPF(<-exPW%BF9vLz+pz?JIUs&=Y7>DZ_2+_~o1l-8qo)LdNR&yAk7hpyUjc&<L= z)RExHh~LMC=Fy_RTtmV?KjF-Z=+~yT<a*t~g5%7duOT6OvqIz1kK4U}xG^!fML3PY zQ|HvA<j$bIJ3G^6X1VKs(35S+RaLw1gT_uymdstaH8rt4A-G~H%wuG_M@zb8Ws;TA zW^2)iL34~eXwA;?y}#|h!R^Ar?#0IN$jR`_%<--<Hq^DqyuItEspqP!=dQ2mv9s#7 zx9hx}zpN}W)z$R0W_!S=%C9#);NbVg#O%qp*3r@OwTrE~yX?Nd?W<8{vvZEQtk|zV zN|H5LgGPX=ey69T;D1YtlFETR00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*y&TK~zY`&6N9F(oh)3hs+U!xs^aDm&vUZae{%Mz>t6d6NpNgVwgoYFIh(3 zy7;emwsT-WPoD8Z&*S?eXP>?A`{nFI5QC)~(-9-qn4TPw8K(^79c_;qX;>yRGhrkM zmgDZ;!yxpe#VVK0K;5Sag0tJFa13pkb~v0)7iDnswA^I|Fc`!t6CSVG?Df&|5A2Mc z!yy3hc-(%<1rabC4w>YwJny3XHeUcC4=@N!Y=Y67XxiA1bfc8ZIN0SO&+|UgKRXvh zUD&C47Dj2YfB}5L&;mV(@PZ&Ly2G|eBm_^E<{w2_CCX`sM~Fq1<B1`}C&Xea%&Iq; zOraAtn&uS5sSu)=8Af8U2<cyQC6^Jh6isJYB}$L*I2jkk+%OUd1{d?;LMoL)BePGk zEL;+-QB0IFnW0^bN?v7?8Vr}lB^C%K$n~|kVljbU#y!RTm7(NDzETiDp<uWw4oSsV zYGtpCl;9o9;t`QtCtYGLmn$hZIa_^(yU7b1^-3X8DwULAxGEqp-;0rcUaP<81*7Gw zBy{A<kv%cHxiuOAn5}W8+b#20LxQz!W_B9d5|f&{uUdPr_um+(w~{uGN$q#<KYaXj zKp75?ByAo;$g$acEF)SxhLA%)^%){~kHK9IDF4aP7lhzE1{2$1^xKlu=tsIy%GLP0 z%U9sB({2~!v2K*jZ{34|T{`aYNox=7f;@(n{C?Iu7(mXM)eH3mdJKaAk6o%=pvP`N zn!Bw|K76H)j6C-5UF2YX)XG2AV35adO6;r+Ja($S4C^s4@~?d5s&8bh#{hC(D_^Jx z-eXexH}KeH7t!J|X}^=NZ1#fD;;{zEtA5=J<`#PF|I{BM#JXLtE~^v(001R)MObuX zVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn= zI&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f(A@n A@Bjb+ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unknown.png b/web/pgadmin/misc/static/explain/img/ex_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d54f5c7b253978b96993ea260828a144395095 GIT binary patch literal 1088 zcmV-G1i$-<P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-s00025 z!qAqu(2ljybgR*YvC*c#(8$fuxW>>^ozY{g+H$$zaJ}Pq#prd!=Xk~Eea7c~!sL0n z;BT|sS)tRx%FtS*)o#A!TgB^2zUV@{=s>&YKf2~ayXQu|=uW=pS;FaL#_4Uz>V?ql zgTmx#uG*ix&}^sCZn)r0!09iw<{+@-AFtyivE(VU<S(@3G`8hBxaB~(<wd*ZOTFe$ zzUOPl=~<%FSE18r!{{2W;}xvqRlw(3!RL9*>ypmuTB6fvyyGgg<`JvnU&H8?(CcKb z+6}7WW5noy&+LiA<Yc7LR>0^9sp2xV<VL*aXU6Do$?BHZ?`E*vFt_Gl#_Mpx=3d3> zQNZYfzTthY(P6#i1*qX$pwV}|;(pHSdCBU($<S58=^e1-60GB4s@Sl@&}p>ZUZ&P@ z%j|o{>5S9ub++Dj%<5;W*ml6=ipuD1!|15M&|t;sdd}^2y5K>(=xE66YQW}z$LM~@ z=wip~XUObp%Itj4?KV3{{{R300d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U z00H_*L_t(Y$L-VoSJF@z2k>#Zm$&&66HySyHefJJgw$z(fRdI186mP%OejOc)GU0- z>Thp&cTUGnWA_LBjqi^;_jC5#=Xowg_45ER0W(yCfW=C5-iGWBdSGy9_=%GlaUqi- z7)9=}agTSxH_7@rUI+w3XtcKw!x1Su^>jKm6Hh#wotx+6KyX3qS=8e5Xfl=jOVUex zCY$SJ(DF(?f1kYIGpjlM+Q3>O|MFk*N?zYUx};D{l{E6&w>hhkH|4iEy=IG*tr8}& ziR$)Hxu#$u2i^f4va_4qyCc)=fD6L<KCfW%UbnKkRKg@awqsLAR5&PNlF7pVi-x=T zA@#A_G0)+r?gu!`8IsoWZc$>r-g5o!YDdRuOx8EdI)ya=f(84cqtfc00Its*zP`{t zvGm*-tI5)xw)yaY^JDU5HB1@DiXyUq6VF9xpNhu9hUnU)HhsCxm`TK0GodYv9AJ>K zpwO8V$2+zpw@(TFp)QUR#cP=s&KF1o75*B>n>;TB;RT6Mw;+beHz%@@2+C4n@q3xe zxX1(rB0fx-PLf_>Qk9e@SL44kfRHrYjx{x*Q0S;ZNGK6#A=nd5v?4T3cRC&Bgw()6 z&n4?oZ*z4HNy+sL?wE4ZCuHQu?RfR}=da`6SyFNV?OMnlOFxg0KS=w20#>Z+^Z)<= zC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!q zSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMn GLSTY1nJ@bQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_update.png b/web/pgadmin/misc/static/explain/img/ex_update.png new file mode 100644 index 0000000000000000000000000000000000000000..a45c53f83a0593704855bb8488871e8e8c9be701 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003#P)t-s00016 zTU$1W!3nA2a+aZzl9IuXHZry4b*9Hbyy(lKSW3X@*Qid%s&!q&>iw+&W5()h$LMIt z>~72Kb<OPByMEiff7`u@<Gpj-zJT1nfd9QPd(rRQ!GeU*?%l(Kgwyce#Dw0(h2F-7 zjMVPm$A{m@h>_Lq;K_;M%!-%U@#D*$;?9iY%%0@Up5oAr<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp{Fb>D#L7+PCQ5nd;rD?A*BN;F{~+tnA&o>));H-n#7It?J{P?cclX;jZoAyXxef z?BcKO;k@kQu<hls@8rJi=CbbQv+w1=@aDkp=(F$XweaY|@ae+v?6&di#PaRM^X<m- z@W|M;qjdlP00DGTPE!Ct=GbNc000SaNLh0L01FcU01FcV0GgZ_0007=Nkl<ZNXPAy z-B#LA5QQ<eL#ah;5tS;UMbwA_5<v)|fIxsm0YgCuG)2mv@BaclIp+XDLzfq>)m}Ik z`zl|u_nwKx@;3iqJ}~+$R5OHe*le~9W_M+Eb)VV);&7ZYr@MQ57tF=s@$q-Y6tOKY zFWZ<Eq^rzltJUgYHW0qY9ImfBj+s~b$~)|Np_(D^I2a5bC)(@vMljMeZ3shERr^4m z0k9j9!To)$N40l*d;0*Il+U+8O{EeF5Mun>Zl6PH7^x9N(m>1S^C~n`i3##!Jnm*; zhV*LqVXP05gphXrI;BEA5sz0XlFizcG0d`H|I-vdaf)Ui`bxFjrCB!Z-`K&F`2_lG zW8HeL^u3$4uQLXA^nuZXrj20OZmUD+*A=A;U0IeplNZl1u(P(dwqr=q)KgrQK@JCl z;>^E+p@=3)q}Ws)l=#)94014dCK_tO3=TIzaIq>bwt5*3%TPQ!V{>4cXY2w@vpi4H z5p%f~7?%#4`cmO#jZGLtp*Uy@&3d0|w^~NK=oCe<1FcLZ-GKRfgiQARl7;%8Pr;%T znUf=*08efhU<o1hL;@WKQ8^qA7C~fLHUsG+pZ6(3LA}y4RZ?t@Jvm83((Co|<_PjH z|Dvj=XrUD8WCI!k&sR*5kA}v!pSNfJ6<IEJ=yr%Ul7estl~^=#V{VN2CpSP8r8wXr z>T$a{bA%j*5fQuxo)|>jZr1{YRBA-{1CJ*HoZICJnIoNCF4LOJQi(<*B`9&BQ0dhg zYo(KD3q<dDK30Jnj^of*LV-ZR+!#3wqPz#EaOo)mPN(zS97+20!yp>N#m*4FIU=Af z#HdEyIudfZoB=prjNI`t<e#W9MZxd)7yi=N)=U1%xA~vu4`}JQAOw$Lx&QzG07*qo IM6N<$g4z^C1ONa4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_values_scan.png b/web/pgadmin/misc/static/explain/img/ex_values_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..15b5ab4079cb8e2c015b4f5f10a3dbf8aa6410d3 GIT binary patch literal 913 zcmV;C18)3@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-siMiW0 zh{12o?m@ljMZW2E&hL59?@+?(R>SIp)9{Ja@MXyCYRT+x%IuWb@tNB3d(Q2G(e0$& z@u=SNj@0gw*6*+3^985jNWbYDuH#$9>o~XNP`>9?z~@=P=Z4YkYscts$mx~W?|Po8 zrNQK8meIkFHu36*?c-qX<6!dYhx6)(@8e(Z<X`jahxF@*@Z?|d<X`pchw|iK_Unh? z@Av20E9lxQ=-Mjk+bZnaD(>4V@7pT#<zLt8_37Fw>)R^r+bZweD)8JY^yOdH>GbpD zU-ji*_v?rF>xbLDiPY)z_T^vG==1U1D)QVa^V}-;<zLa~^7Py)_~l>q+$#9yU-|2Y z`s|0!=JL+v^7-ap`|O6y<?;31D)-$g_}wY`=3mR?@%G&+`{rND<M8?2DahmS`Rs@M z?1snV@W$fr{N`W%?1shR@B7{<{N5@3=3n>SDf-<h{^no8;O_n2DgNw+z~An<+wA_{ zDgWkQ)amoS-tDc{=`>ap0ssI20d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_ z00FH@L_t(Y$L-b0a)Lk*24Ek?nFomRW_gGUK~X^z7hFIQqoPPyTuOQNU}g{;#Yj~u zhm?Jq%hywM|1~5M&-$-bf~P9QA@C)YD!#&4B$dhJ^6-HRlK><UDZb@$)Hi|e6h+aI z7lL#eAd=5jtC&#LT8)Xk5M;BM1g#-eV_6OzX@=ukmluLU0gw}e6wC6MaC~zhM3C?# zXpU=qVA33nA0Xiih4FYO5~N%P_eS3qM6pMZN(IEs1gO_R%)p!pq$!4J!B~W0dA{*T zU_hti6P|CPal)1$2<_;=bi0@Y8wgGI=I8hOm;|k%FdTl$=-8HJWkw8nG`bFqIFuv> z5m{ALg&>p3bzpku)=*JRlO)sW-M}cOX=((S&+i6irfAxdAd5xpz^qoW1LG6e7Dc)D zP+)8u6H)Rf`%_@fM3(#wc;Boj%jm#tw?0u-yn)kXbuBtDXA-pbh^`yxxHJr711}%G z-3~o|;r(g)dX0&(b{s2Az~Sh+#{;pMQ)_F3i9?ViuwB>2PwdUWSk8WbK|JGSEO{p| n8_Tjb@b)wQYk!?*{c(K(wSJimSdJ6(00000NkvXXu0mjfih%ky literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..1f858be1cee3f5d8f2b67f55d730e6d3f43e9b42 GIT binary patch literal 2021 zcmY+EX;jl^7RCc83W}o8IHN*Uq-Zs4LRCbI4z#9NL@EWMAP(RVtW_JR7PVGNRRkQh znn<Z&+4l&9og#vPgai^o2nm4%Ldc%~mVd$)>ZI+bIp?|eIrp6BcfY*ny;<R5pE}rY zw#Q&F4*2825f=CTvsT+!`tIrLKVmR8nD7&)Lo8!yi~K_7@W2ejo`r{IVXgw<s|_3_ z!kB^j<Y2EH=#lArWI(q}|3<EVGYj-6^t~#5uNt6hfPO95rvv--AOirIAT(eR1hF7+ z5QgYdkUkBv<PcAd3@Koy9O_j7{d#~2fCCmm;Oj|!w*=^s0=-i}p9~aeP_`wefEcr2 zpAw`ifwvlf34*O6ZTq;kU99Vz&~YuRR4_{k4X7Zd3S_9Del^%QrlAQne64|}K{y(i zt$~<Y=oMdGFHkp&G_NK4F)hl~B12kuPzMd@K!!yi$b`UZo~m|4Mdho6I#i%DjOq<M z9WtzkIeNHiSV<jKH;ifKmX_zu%M0dZrVgs)D(m=ay=jrjVm*HR_}3RN3JMEv+`O4g zBoYXO$jHd3=;%|YB90zC%F;s>TxI33vX-xUB~aHl((Ytrq@|@%U)9qY40=Dq-`~HS zqpad7&!0aZckbN9i(hHy78aJ5xxA5pfPjgqDKTOk1mJRxqJpbv9oIs0OT5uhJRUy| zqFLG5J#Xns)BF$smvI#3Tt!t)O>=A8;_@Hk5IPPSMG!h`oS!rp*#J~MqN*EJ>p%#c zUz|csBOt=DP(zB!VZ{tG7akriMT|lS6+nhT02%<Gx>1#B$t;G9V#_KR<$_4z%a@*> zo*o_^LKtNMQ0b7OYf>);joY_xhZmOkATp*mJbC)`?KCJwOd=Qs4QN7Qq7DEnh81;u zRe5ElVbMHiHs8K|djc|6@l>5%T|xkrD^+9)WpR0#I;t83A>*Ri#l?jS!YmM~<SBU& z!UiD;Y#f78K4chz;jSsY#9-n=Fb9FT2;3pj4XR-QfQn(`FpLZ%$OwWo2-Q5jfsYsj z1_Rad`s3QxNv+U;3JnGkiqgh4%@bOQ(Kvw`d*lF94M|NV)}cJq@&~L^Bf`GG1Sy0U zEQ8&Z<1r+QAOEX9VO~6f!K~Pd4?cSOcz;6tKUOAMee%H$jN1e32N$-*pHE8ok1~E* zE>ld;&dew`IXXIT#9}wR=R|q*^a=TK(y`GU9$sD?W=(frT}8=DHl6NZosse3Hr$SX z%c@c|5u1IJ34Z?mO|-Ps_YR=W&rpZ84i0TOIXStxA(@~5KsX)g&OhNpd!CnnCORcW z+ptTsn-H@{BoqqA$3@~p_wQp|?#5;p7Z?AW_fzRd<r_N+8ncU@J$qJNou8lI(NVF> z6X)vcTJSJVAwldPq#qdynv%)1TCMVZ4Bu(jI{rrInmc9gJN^9FBTRP0y`O(P92jW5 zdWV}^aZyo%wYBxt<SYj}yWH$K>-N3deeA3@Iyu=qxtfg6%5}gSQyaKpp&SN#fHA}z zWN`)ual20B?2d4vbeEO3mh3E{v4@X^?*A>Yqp0D--`mUD+XJd!VJk{kcaYm<vPJHJ zN7%x*y1RX4B^Ml%iI*;ds=X1tRi)J(2P~ofGnCR6>g!iHH=^}w+KFHNzOxU{-i*b4 zQJzK#YPzyBj9Od!!iUsTBO)o9n>qQu=VBc?$VB%wSnDQ6<CWH(U-AW5PeR~DQ_VpV zWpAu4e@9jb3#lXSi6=Nmc@jni<b5RnaMmwPp_JM)|2@O9eS}@PE<~AId#R}@Z{Pk) z5^H`#lT!)Z`5yLU1^Ir-r6%z;T9|~E<Z+zkSwr~tUro9@$)fz|wuEyF-#;ST1g9K) z?njjVmY2Ue#m<U&aIK)>_6F|Kr#}!LZmdq4t)E%&_+|eF9xu&T{<M5kbm(=S+T67- zznh>ah!wYmx|EY6USeI6-05#ol0W_ir*KtD-b7p)wrHhWR0i!VCdEqOvz%$l$;MN* z5eUttCkw3kMGr$*ryr3Ic*MINA}tIwmt+Qew~kAs4bCMY_AS^oAT8ma&qnUNG|Nix zo7NktDI)t5l!%Ck=q5fTj-)#^aov;Z`21{&crnV@GWzx9uVT_~{o%Pgo|qLGs;azB z-QsiypCld3Uoz>1Rz>Sy#HMQ(_2L$vHNx2-P#S|-oAhwY7N;Or{AVe|Ji8S*mur_} zUta?Ya`t|UD@_VJOzu2u``MSCL#w<#7pC4ecH-8%e*OFRv8MJKom&mz7?pk_CeT(> zU;j<kgB6;X<&p&Dc*n`YBk8D0L}H({<2Ae)sZ_3v=7dTs7*S4fALot1Q`3|CFH1Ua zEv>spZkUS;IvhB0*VZfc*2kR$8$qMV&GF`9=Bb`kYQ;InbPcI<ghKUlHC!c$#O(_q zF3}_PiE;fcptNgw9=2)Rx~C08n<bf-3SS4M&$s33Cd@_ax87=y&%N(GpBvXre#-aS zg_{hw9k%8hqUfr^Gi+XyODNfFoAK`5yW*7X#py09gKaRar}nL){ZzKiaxmOeL!wg? z&!;8@Bz%)(F^sRbk2lW87w7GB+Sfb4Z(o3)-yU!O0B`RDdG4<N2VA<GNWAdf-+=eQ czkol}0p1_|4Gd5sYb*c;9}*T^cPu{Rf7sxo_y7O^ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..b51e0b3f4c61ba166b69bd7f32cb23dc8428429e GIT binary patch literal 1965 zcmV;e2U7TnP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700093P)t-s0001q zx!X2~!Eep(LA~ikzUg(&?|IPgQNrp}!s=JU>VwnpiPi9C$n0v#>~6~Jl-Ti^+VOnO z?SRnjgVF7z-SMd2@{ZK*k=5>#*6*+3^8}~i2&m#nzv)fE=@+fz9k1hC#p`0n>oc|G zIJf0JxaD!n?0C-XP`>9?z~@=P=Z4YkYscts$mx~W?|qB4rNQK8meJ5eW%S9}@VCtG zw#)O!*Y2~(?y|@6#MJDt#q6)d?5@M`!O`!)(CVwe>8ii(zRuzA_v@d#>YcjkoVn?n zxbL*d=$W<Wn6&4Yv*nbp<dUxIt-|7tso{*L=%~Ec>h<ZIxapd==9aSKk*wp8tKf>I z*6H-`w94q2w(YUT=9RJKl(654q~D06=B2rdKT%UnPewyTlyrWDZFV|3I(I%y#G<Zt zWNL(KbcAtuL_0lQQB|jbj)G`#z?`UTJxGCOZfRU#pg~tqMoH!6<?{0KiHV8-|NpSC zu)V##R8&;h*w|rVVV0JbZ*OnP%F1U^SJdhBqobooM@Q4>^OZnUe0+SQev3swK~YFc z(&zKMLtn3jlUz(tb6sRlLr2b%q)|yse`0FT=JL+w^5c=DVm(EGKTgi&@@ZOMwU(gB zm8FAjb)$QS&y=Rj<?+;<uYFx+W=~hCL0V{6TytDwd{|@He3sdms>|f@jBa<hZiAC< zc(OuV%H#0J<M7I)vA>3umU@DWa(Tz&@QGq<#^UczJ3z(Z@5Pa!#dVCr;O=lzTe*jp ziD`1#eV1`sU}jTT?7GS1p|$F^#p0f^;+?SJoUiD#!|1ZX-<Yf4m#XHlzviyI-Ib@^ zl&9U3rsS==<g2>dk)+#@qS}w5<Eyy9-|p+U$K#)~<DRnMo37xRt>Brg=d!@wmZ{#A zsN9mI+K-{yj-a{Q?BSfS)_9WDcaYU~kJECD(r}5;ZHCWmgwJb(&1iwmXMfp@p492{ zzTWMv*6G-LmDhTd)O3!~Z-~xng3M-q&S`?qX@S~~q2j5weBkSj00001bW%=J06^y0 zW&i*H0b)x>M0ugy)X)F`010qNS#tmY07w7;07w8v$!k6U00Y-aL_t(Y$L*APR8>_J z#_6U_Hcx6c*gRSBHar=`ATcUJ(Ht;saO%7iG$Fe8?l;``uHGjvHK9N)P1H=2tk6nR zgOUm|qrd?tL?l2>Amk|uYT-F2DDLgiTCU}4^@sb9ec!w5{MNU>{oQr^{La^ZT^9(f zI_$m>;lfUxJ6|MRe95JkbrCMV;>xS87OuJWy6bNcZtU8v`%QvRq*IR`H{T-MdRxz) zw+naNdDq?d2>0H1{{s&SU3>L<=waa;sXW4G?y&35`kPGt^Z@~Zfq?-KU^bh3L+_xV z;1CE2?Gx4)9u1F(cnoxisb4=6LjofsBh6s$|9I3B5cK3z(V@`i>6n-S5I!(Ac8~!X zJh(mbOw^Dd2#$^(8VX@C!-j`LL~LA~5g9R}4e4)&XQPIU42DrdpL;$G1`HcMFaid} zz3}2_pU9Z8<Ho;4EH6(W6XO#InKU_`(0XM`B1uXjuO|CKUK6DR8Lf#nv|A-ahoT@Y zC;hLuP@SqrrcGmr#fo+(s$)e_Mvd4}Rp>)RH$@zx+n_RiIzv)q^r$GgC94zV*Jnr) zN5q*nR8byp@G@%_L*B5XQ&iD|vWA}7sSb$^CMsz*+TVQ3Cj#jda7ii~uT4cmnIbmS zG7QL^IUI?%O42x064O0@d6_AS+zYx=^vK+~44FsGsBb&bYO%C!Onb+JDn%4@r0S9R z^SMgMM6%#r3rSkIFq7r7D3fF^&L9gCNk#^lWKdbMgfE#TM=b9xCGXE(mPUUrPyT?c z$oi1KH+osQk|L6uC5PHa8mh}_en_XJGkyGtlf725^~kDKf2t^GBbIcLX2T-4qN^2g z{!?Z3YVPGzicDDMV#zUtemJy$_BlgltT7;K*Yb^JQzY>V4egRTl@G@Dn>~gNCMC?% zBkR`vt+HNZC)|9q){a#+Y~aY36iIW@12W3=u!kcgm3vwGFNmVqbKIKD2eY&8@VT+v zT#k%hLB9Grdt**s&c>8)Xcpflv!2RxF{-p8-{t4$7eK-Hn|{~~KNc4L^fMF{Z`ryH zwwLVKxyyj;-pw}#tUBzz5ZF^%y0-u}m+dRx5Bn>ADK3Jd%F2@Mu&b)7TBkxUz5@r? z<p-sCd07Xc?9i`=3!$Q>wstF2*8Nt$6RM6JY4Em3Oh=D3HXb`_@`Jru$4`_&`QfIf z3Mj5^Zmxuq`udYqP~FgQ%Bxq&ZEVbCDw~d<I8+XWO*J*eu%)@Kt^{_RJpFq$MNa7v z%Fu7jpL%KUVq2?=KdM`x#q0I9=r`7Sji1fN&e#8|&HxgQ2avxbUitt403~!qSaf7z zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6W zZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfomvcc literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exclude.png b/web/pgadmin/misc/static/explain/img/exclude.png new file mode 100644 index 0000000000000000000000000000000000000000..bd62eef6410d9315857d2e6d246770e8b65b8f47 GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47y|-)LR^8|wi}<ymTvVw_QrY1 zLC3?d^*UDhFWLA1|9`)wM`KREbvXQ5A-=(6%9fR9ZhU_6^4^pwS28lLWMw^=HS5>= z_isLZP1<@%wQ`Qjk=K%*nNgG09JqAnY+~Zm($d$dsZT2^E~KQ~e)?Lsd6{J1L`ko# z8QYH^XzhAZSorVPuP+-md|tBT-`~HFYif>6nkJPuNuqp?YIOD56Ib^8`rV6+d^K<0 zzkmPUtXQ!pGFqZ!hGg3swe*g4XK!wIaz5qe_HfFSrwbQu^AC`0S|K@Qk7Uk-*~hPM zEhsq<82I=1?;BI6UhV1m_vg>S@bIm*jgk|0NG?2Of9R!T^@7Cpr%znEwc5~Vm%sly zUEQ5NKC5l*c3rqFx8Q{2nrn7@9?A4<w%>5&&c`3`Z{FOOoV;9Hdxfs<!JM4Ox9?6m zenWfBW$A4XY?hzYUUH^<`Bv54PXhWDq@H_cwegx-ao6F7A05CjWh@Eu3ubV5b|VeM zN%D4g;b^-zwF=1LEbxdd2GSm2>~=ES4#-&V>Eak7aXC5R07H*Y2Gbdx45l?XZ+LiQ zWMmY~)Ws(}c=qt=V{riyAu&Nw;pq&V9$ucOPn<e=Qd>hyv$&ZhB;@K9Q<JS*N=v?e zImpD;=5|bN*|M}_&%~xBFluK@M_UI6S4XqEt8Zx7+`W4C?)K%=xA(7?_c&m$V4z{4 zVq&6Wqh!RTA|NX)Ek1w3j45*_&6>t1bmBw`i*--4qPDWM%7n?><t2V{=CjN{U1V)w zV3-jtUHUai{xs0(swJ)wB`Jv|saDBFsX&Us$iUE0*8qr2Lkumf3@ojTjkFEStPBi} hcbK)IXvob^$xN%ntzp~MJ}aOG22WQ%mvv4FO#q89Jv#sZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension-sm.png b/web/pgadmin/misc/static/explain/img/extension-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..432d2f44231c1f88e787091060efc5125d80ef64 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E0BJDv+cp5$Qv6qzrVk7 zW3&9@vzBik`G5Ho|K-)uTicc2-1GkNGyU0x%oo?3fBedPak1gnHlr`^;(z|izO~Kb z%lm|1zjI$+bN~H2|Mm{mcMpR9{3*J*S>f3^`;Si}e|^pQ`={jETDdE$#Qyy)dv><$ z|KAGswyocQwlbCk`2{mLJiCzw<Zu>vL>2>S4={E+nQaGT<aoL`hDcoQ?f2wsP!M2o z7l{eDQ+~(c|9@BE84^1Kx361bY|Bu`qQb-J62DBxZ_<p5BE`pwna}6wxpa1%>e!Vz zahdU=*X&ESFOpJE*&;e)`qd3*DpaT5u9JDLS%3P((k)@<ZbaLzV+h!Of4=?`KK92q z=3fE@l4^--L`h0wNvc(HQ7VvPFfuSS&^0vDH82b@GO#i+wlXo*HZZj^FqrpFZxxD$ o-29Zxv`UBu152<5plTB<12c$*Q`1A&05vdpy85}Sb4q9e01}k2!2kdN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension.png b/web/pgadmin/misc/static/explain/img/extension.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732 GIT binary patch literal 996 zcmV<A0~`E_P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%`cO<%MQ2zLf_6I6&9|zdd99>-@a*2m!Junh7N)|bRf|-bx|zVboSKha_w(lG z;mc-L4XVVcQjb)R!IoN>UTm6cdTlP+)48aeY_F(+!qvh)fIq$I$ak@QM1Demb2p-y zZNIpg%*U?Z+|0eUmR?Q)@#@yLtA3u9XFhv8mdv0tb~C!Ok)4xckc3Wsa4?*aUD?pH z@afX-<;s|gP-<HecxWLITMn+{ye)Dq{QLL&`11Mo?Dg>A^X%E{;lk+My5`xk<JGC) z(V?J^Pa0qr9%URUZYXJ}aH`|EXsd7=V;MkvKHbcisFznYY9*e@qsi^kq0p+c;k~!# z!?5MPqv5li->#6?p?1NAale3n)0NuDkgb|nMQ$vEwur;)&X(P%klLe(*qwsbn0(Ze z&%lqBg+*3S1ZY?dnutTImr{GNfpyZ2etkM9XCNqTCtr9wihVOAV;iN_u6D(TK#xcf zTn`v!7(bOtw4`b=XCQ>Lht=`it<|(#mtSF?W<QQcm$;T>m1BZ;G0*SUx8%WGt7&4B zV3D+tb8RIwgF3Luu#bN^7G4v==*yVRp-_@kjmeoSdoaG!zSzWv!K`UHUKC!MVuZSj zaIAJVdpAyF9vxyClh&g+jY8GGe$u;klYuouT@*iVD?w)>Y;7EsekVC?DRR1gZ_tQZ zyKv99ZOyY~z@}84hBK{_JHn(!l6fLVbTnhFZfMSfV$6Lul0qhGC2*Z?NP<TvhBL~q zUB|0c#ivccpg)Ro98G#WT*`P>$a6}(W;2>aI;l}Wz+t|fIeljlScFSfreaXWZ%f2# zMZ#t~zg?k^OOAUphI1*4cr3V}Qns8&igY1@Y#D@Y7H?b$T8UCtsbn_2S%i2!rk!)h z!>EaMCcvamyR?(W!KK8$qF<3+9BCaAUJ)8<9X6LmEss1DV->ZTL3e2=8EP9)hfaum zLy>wXERsEdsDEo(3zmE$ex`jsyImG&7=LOOfol~TcO*%INEmJ%7i}B|YRn1%0004W zQchC<K<3zH00001VoOIv0Eh)0NB{r;32;bRa{vGf6951U69E94oEQKA00(qQO+^RW z0~-xG4!&HBF8}}lR!KxbR2b7^U?3j2xS;VvLXbtwTz~>0W=QhVA)yH_FkL{}1;huk zpaKCQKz@=7s`{i97i0@vl2TS8w1C7?R&G7y;)1Nm<<OZkC{A-h<6}A<CjbDaP8qDe SR_4e60000<MNUMnLSTaX-^L37 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extensions.png b/web/pgadmin/misc/static/explain/img/extensions.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5 GIT binary patch literal 1017 zcmV<V0|xwwP)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%_fSk!MS^xZ(#^N3p?R&Od+_Yu$ibj%T^6RorB#bmn!1_5x}2JiUH9|m=i$p{ zRt>7esZx(rkHMB&m|kp}YkF-i+S9qHoNTYCfx^|oK7c>H>Bx7neMEjjfO9vZnQgzg znaszo-`vc-ww7K_0rBeAwyS=gm1jPCJeJI$Gj=n&vyq*XV~~VSeQ+?GkzLu)v+(KC z?&Zpui%@D?5_o7K5L*te<Gd|$E&TiU`}p$t_U!fW;PdR+>*2!a-MZ%4vg6gM;L)L= zk53w479M3BDQ+lfsBo&|xoE3!8)F$jd_LXGn5dUmHEJcE$)m~b(xK3*v*EqB=fkk& zzN6u@o!_pI*P(X7g>k=tf76xP$dIj?SVe9ugSLpn>&}+lsF2#DiP)Wj)|h<Mlh449 zm4!uCPy}dL4Vs8UtCv!Hv4M5cjedPPC}$ujZ6{xNJBocXBx4(;)vk8Mhd_@=5nK-# zWf(t|O0=YEF=rrzvxn93+^yBLT$f*Ao@PIeN0+#kWR+urcQMcJ*SF-sT&rnflVFjw zkaKM%G=n;@$*_-qITl_M!syGG&7n||RE^1*D|;}$)4tfmhrz6AIbIZAnqq{yi*T%V zHhVWtV;&u18I#tdIE_NpzkbrYc9VfMLtPX<ZYx1&B5Z9Om3}8VZ7FiPes9o-TDx%1 zw{6X{Wx%FXorW{5k~_krMv{3VMsze|t!`+}gJR5mHj+XnY9(-;Zb*VhCx$c1uU*Hh zRmG=Gz@R^havV*1JY33nR>*Toyk;|+MLMZbK)_+XojHAH5m<yvR;FT5#&1i+YDL0k zJHK6_k4uhwGlp|1i+C)!pi;J+M~ZYIf@~RtZ5D4_30jF#R;gq*y;+2KJ*J&=$it|K zbtb^1PrI~}#=)h;zM@}|T^wm05?&D+Y8^J0MJ<m!6k`>&nL&4HC>d%SP=`*4d_$3X zCoGaZfT(|KS__tZB7UZQKD%8OXc&KL7J+LO8+Rm0f=C!{9T#mJ7UDFE00001bW%=J z06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru+XEXB z6Cp(Rbcp}}0B%V{K~xyiU68R2z#t3+nS(tt!3~hY^vGg42FL=`EENNm0{M!6-y1;) zQxFazvL_cK*b<_okFg0d8Hc#V=Eh`)h+yZmplehnlNZEdtgQ@hX0CNeIWEpxw!oyN ndc~tsp9TlidOzOC&-)*|KH)3pD2ngr00000NkvXXu0mjf<KNUz literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable-sm.png b/web/pgadmin/misc/static/explain/img/exttable-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..acd43cb8abab6ef38daf34ff6d7544153a11dacf GIT binary patch literal 612 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47`X#{LR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)^XY$8$A0G@_?f)(TiB-0o~u9DE`4h_ z@3s2Om(8dDdI7mh-fGNz8JxJ$(RuCl>$mUSyLbQo{YQ@;J%0Rn>9T9)mKA9e*Bv-; z!q9k*y7s}c^63vAJOIkOd8|>@*q@f(clYkyWy_XDM0Trbo^<nAscUdhS#3sp`^5F@ z*S~u8DlvJNy7pxi^{qR09)J1r<?Gk4&!4|-WV%sNW#!y?Ya^o8sA?W7EL!yO<Hxse z-}X<~s-}6=(71d4{Dn`SK5cATs;+%VU9<bdiL;%Z6I)tVJ$drv&6_t59=vw<+ErTC zQw{Rh4~>~Gc%JJ_00swRNswPKgTu2MX+REVfk$L9koEv$x0Bg+K*j`57sn8Z%gG4} zOa@Af9Sp+8+}hIC?Ck2|<}MBG)BEEc0z4vIL{>Gq^Qb83DJpS_PM9=p;?&9E0U<$c zTq{<rTA7`ZmHE2Bfwko87hay;9$%lc3z#+)6+IK17IrPoEP&B6+Pa$ET|Heqd_}|T z-R;Y#Z{6O%UOwc2y~2g=!)h89Dk9JL?rkX8V67z4`B96(W2)e}i60vRfNoPQag8WR zNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTd cHGouG8JIydoSGiG2B?9-)78&qol`;+0LVQH?EnA( literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable.png b/web/pgadmin/misc/static/explain/img/exttable.png new file mode 100644 index 0000000000000000000000000000000000000000..5d84035feea62d53d457481178b1bcbe9622f856 GIT binary patch literal 793 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47;6K3LR^7d#i`GGFZ`c${`aEG zUw7Sjd-49u`;VVLefIp>vuC#+K3#L}dGf{=db3}2pa0)_=3m{3Kc$C%<?Q>BxZ_*c zrqAAMJ~%9YXTIQ#?wnU@GhViy`J27(hvTw$W((iw&U_Y~)1HyF{qEhn_wL=hfB*i2 z2M-=TeE8_mqsNaQ8yXiV>iW%}zd>1TV^GL$BjYL^{S(WU9oVt+prXnmSNFZkm#=*C z<jL~o%k>TF^o@>PyZ-vst5*{zPLflcU|_QU>a|B#uU=JF?bJ2cziipY_3PKae*OB& zm8%-sEqaEB)ikG?m>;=w=lPpAZ{EIr`|{<>zP<^HDjPJkuS}Y>_5J(zA3l8e^y$;P zckfoNT)BGn>N#`fDXPqIbUAEeo3EjBs<&_JrcIlkKYzY=?-6CSwcft_U%!6i?2@ga zbAH+K$Dcoc{`&RnzI`WD)Hj5LAKkcd)7Gt9lT#YiwN7;R-um|K+wv9LmDM(Tcy0Rl z@#D5_+u{=nRW-JDc3)AL{8UY|HzVudq)BroPg$ri@$mwIO;dmoz*rLG7tG-B>_!@p z!&%@FSq!8-z}W3%wjGdh+0(@_MB;LCLV^n;4-Zd|&l#OHId5d<%!#>Uvqyo^u8z@B zF;Otku#nSp1DBm9qhscRhMqMtE)H>yfu51Bp}w)6&cZqimabjQ@@VyoS1+4cMR<97 zd#?KUoIRtfbCAhvS=cqRZDrs1`uxr%FfOPQ4>vF8_xIM%-_X$2-@kPI{CbCkfC7#P z2U8Or8zmzxD>XAS4xIy%;`1lWcrs_sq*>GW#5zu&ICF}R^VG?+r}Y`QMZ`qYkF!mE zGG*G-@CFvG)vNY8H+eN(zQmoCbx`Y7z#e{vFBY0Te&TE7f!<Rsag8WRNi0dVN-jzT zQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTdHGouG8JIyd UoSGiG2B?9-)78&qol`;+0Q{<O$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttables.png b/web/pgadmin/misc/static/explain/img/exttables.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dfbd454ed33727bd1deeb87c62f8671f6a5a03 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47^MPyLR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)(1uT&ufDx|_ipp)e^tkR=O6f)yz^Vw zrq7<MKiDpPYdG(<`plR2?%iuX{nra9vgEDdjF%cSU*5le-z{*Hjoqv(SFS&L^yu;9 z$BCh54YV)SY`ps5!GohmFPT|vP}AIAUOws6@q1>vXAHE?^>wU&`SRt%hYy!6TNV*D zT}|t>v;9UL?W?Amt7goYwSN8jSFc`8IQ7}h=Aef5HBHT(=Pz7){rdI(-PetE&Kqf+ zTC?J?x9>_dt@Dk|J3fB=`1bAF+~nQb+SeRSH>_B(;_1_;Rn;?8HFg`BEWUQ_zJ=bg zri$H9o;-Q;=FOu=PwX9+YwPW<2KnxXa>IqjgMEvDp~F}b<QL4~@a#q!ki%Kv5m^kR zJ;2!QWVRiUvDwqbF+}2W?0HwQLk<G27xhdW8XmB4zY~jTVks}b`QPk?8Z+O@ht}mE zxDUR+@ZDiy$V$_wu1ha@gBJAuXUmw$IQdLNWLm+2wv7?FW$l-rva#qG$_eeUt7l;6 zYfsQPQ#3I{XWjwDPG7CLC)J97I!!#j(8XtG(AulgXTzi?C<q+hI5%(o`R%TodS@Ig zFq!9*{+X5YhEDkFv(xUs<#&JSY%y0q+H23fcl??hCZB62%C0l7Vc_x-dugW}eiG<> z)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!XjU}|MxU@=ow4n;$5eoAIq iB}9XPC0GMUwUvPxM8m1+p=*E|7(8A5T-G@yGywoZHZsuw literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/js/snap.svg-min.js b/web/pgadmin/misc/static/explain/js/snap.svg-min.js new file mode 100644 index 0000000..6567d19 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg-min.js @@ -0,0 +1,21 @@ +// Snap.svg 0.4.1 +// +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// build: 2015-04-13 + +!function(a){var b,c,d="0.4.2",e="hasOwnProperty",f=/[\.\/]/,g=/\s*,\s*/,h="*",i=function(a,b){return a-b},j={n:{}},k=function(){for(var a=0,b=this.length;b>a;a++)if("undefined"!=typeof this[a])return this[a]},l=function(){for(var a=this.length;--a;)if("undefined"!=typeof this[a])return this[a]},m=function(a,d){a=String(a);var e,f=c,g=Array.prototype.slice.call(arguments,2),h=m.listeners(a),j=0,n=[],o={},p=[],q=b;p.firstDefined=k,p.lastDefined=l,b=a,c=0;for(var r=0,s=h.length;s>r;r++)"zIndex"in h[r]&&(n.push(h[r].zIndex),h[r].zIndex<0&&(o[h[r].zIndex]=h[r]));for(n.sort(i);n[j]<0;)if(e=o[n[j++]],p.push(e.apply(d,g)),c)return c=f,p;for(r=0;s>r;r++)if(e=h[r],"zIndex"in e)if(e.zIndex==n[j]){if(p.push(e.apply(d,g)),c)break;do if(j++,e=o[n[j]],e&&p.push(e.apply(d,g)),c)break;while(e)}else o[e.zIndex]=e;else if(p.push(e.apply(d,g)),c)break;return c=f,b=q,p};m._events=j,m.listeners=function(a){var b,c,d,e,g,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,g=m.length;g>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[h]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},m.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(g),d=0,e=c.length;e>d;d++)!function(a){for(var c,d=a.split(f),e=j,g=0,h=d.length;h>g;g++)e=e.n,e=e.hasOwnProperty(d[g])&&e[d[g]]||(e[d[g]]={n:{}});for(e.f=e.f||[],g=0,h=e.f.length;h>g;g++)if(e.f[g]==b){c=!0;break}!c&&e.f.push(b)}(c[d]);return function(a){+a==+a&&(b.zIndex=+a)}},m.f=function(a){var b=[].slice.call(arguments,1);return function(){m.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},m.stop=function(){c=1},m.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},m.nts=function(){return b.split(f)},m.off=m.unbind=function(a,b){if(!a)return void(m._events=j={n:{}});var c=a.split(g);if(c.length>1)for(var d=0,i=c.length;i>d;d++)m.off(c[d],b);else{c=a.split(f);var k,l,n,d,i,o,p,q=[j];for(d=0,i=c.length;i>d;d++)for(o=0;o<q.length;o+=n.length-2){if(n=[o,1],k=q[o].n,c[d]!=h)k[c[d]]&&n.push(k[c[d]]);else for(l in k)k[e](l)&&n.push(k[l]);q.splice.apply(q,n)}for(d=0,i=q.length;i>d;d++)for(k=q[d];k.n;){if(b){if(k.f){for(o=0,p=k.f.length;p>o;o++)if(k.f[o]==b){k.f.splice(o,1);break}!k.f.length&&delete k.f}for(l in k.n)if(k.n[e](l)&&k.n[l].f){var r=k.n[l].f;for(o=0,p=r.length;p>o;o++)if(r[o]==b){r.splice(o,1);break}!r.length&&delete k.n[l].f}}else{delete k.f;for(l in k.n)k.n[e](l)&&k.n[l].f&&delete k.n[l].f}k=k.n}}},m.once=function(a,b){var c=function(){return m.unbind(a,c),b.apply(this,arguments)};return m.on(a,c)},m.version=d,m.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=m:"function"==typeof define&&define.amd?define("eve",[],function(){return m}):a.eve=m}(this),function(a,b){if("function"==typeof define&&define.amd)define(["eve"],function(c){return b(a,c)});else if("undefined"!=typeof exports){var c=require("eve");module.exports=b(a,c)}else b(a,a.eve)}(window||this,function(a,b){var c=function(b){var c={},d=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},e=Array.isArray||function(a){return a instanceof Array||"[object Array]"==Object.prototype.toString.call(a)},f=0,g="M"+(+new Date).toString(36),h=function(){return g+(f++).toString(36)},i=Date.now||function(){return+new Date},j=function(a){var b=this;if(null==a)return b.s;var c=b.s-a;b.b+=b.dur*c,b.B+=b.dur*c,b.s=a},k=function(a){var b=this;return null==a?b.spd:void(b.spd=a)},l=function(a){var b=this;return null==a?b.dur:(b.s=b.s*a/b.dur,void(b.dur=a))},m=function(){var a=this;delete c[a.id],a.update(),b("mina.stop."+a.id,a)},n=function(){var a=this;a.pdif||(delete c[a.id],a.update(),a.pdif=a.get()-a.b)},o=function(){var a=this;a.pdif&&(a.b=a.get()-a.pdif,delete a.pdif,c[a.id]=a)},p=function(){var a,b=this;if(e(b.start)){a=[];for(var c=0,d=b.start.length;d>c;c++)a[c]=+b.start[c]+(b.end[c]-b.start[c])*b.easing(b.s)}else a=+b.start+(b.end-b.start)*b.easing(b.s);b.set(a)},q=function(){var a=0;for(var e in c)if(c.hasOwnProperty(e)){var f=c[e],g=f.get();a++,f.s=(g-f.b)/(f.dur/f.spd),f.s>=1&&(delete c[e],f.s=1,a--,function(a){setTimeout(function(){b("mina.finish."+a.id,a)})}(f)),f.update()}a&&d(q)},r=function(a,b,e,f,g,i,s){var t={id:h(),start:a,end:b,b:e,s:0,dur:f-e,spd:1,get:g,set:i,easing:s||r.linear,status:j,speed:k,duration:l,stop:m,pause:n,resume:o,update:p};c[t.id]=t;var u,v=0;for(u in c)if(c.hasOwnProperty(u)&&(v++,2==v))break;return 1==v&&d(q),t};return r.time=i,r.getById=function(a){return c[a]||null},r.linear=function(a){return a},r.easeout=function(a){return Math.pow(a,1.7)},r.easein=function(a){return Math.pow(a,.48)},r.easeinout=function(a){if(1==a)return 1;if(0==a)return 0;var b=.48-a/1.04,c=Math.sqrt(.1734+b*b),d=c-b,e=Math.pow(Math.abs(d),1/3)*(0>d?-1:1),f=-c-b,g=Math.pow(Math.abs(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},r.backin=function(a){if(1==a)return 1;var b=1.70158;return a*a*((b+1)*a-b)},r.backout=function(a){if(0==a)return 0;a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},r.elastic=function(a){return a==!!a?a:Math.pow(2,-10*a)*Math.sin(2*(a-.075)*Math.PI/.3)+1},r.bounce=function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b},a.mina=r,r}("undefined"==typeof b?function(){}:b),d=function(a){function c(a,b){if(a){if(a.nodeType)return w(a);if(e(a,"array")&&c.set)return c.set.apply(c,a);if(a instanceof s)return a;if(null==b)return a=y.doc.querySelector(String(a)),w(a)}return a=null==a?"100%":a,b=null==b?"100%":b,new v(a,b)}function d(a,b){if(b){if("#text"==a&&(a=y.doc.createTextNode(b.text||b["#text"]||"")),"#comment"==a&&(a=y.doc.createComment(b.text||b["#text"]||"")),"string"==typeof a&&(a=d(a)),"string"==typeof b)return 1==a.nodeType?"xlink:"==b.substring(0,6)?a.getAttributeNS(T,b.substring(6)):"xml:"==b.substring(0,4)?a.getAttributeNS(U,b.substring(4)):a.getAttribute(b):"text"==b?a.nodeValue:null;if(1==a.nodeType){for(var c in b)if(b[z](c)){var e=A(b[c]);e?"xlink:"==c.substring(0,6)?a.setAttributeNS(T,c.substring(6),e):"xml:"==c.substring(0,4)?a.setAttributeNS(U,c.substring(4),e):a.setAttribute(c,e):a.removeAttribute(c)}}else"text"in b&&(a.nodeValue=b.text)}else a=y.doc.createElementNS(U,a);return a}function e(a,b){return b=A.prototype.toLowerCase.call(b),"finite"==b?isFinite(a):"array"==b&&(a instanceof Array||Array.isArray&&Array.isArray(a))?!0:"null"==b&&null===a||b==typeof a&&null!==a||"object"==b&&a===Object(a)||J.call(a).slice(8,-1).toLowerCase()==b}function f(a){if("function"==typeof a||Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[z](c)&&(b[c]=f(a[c]));return b}function h(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function i(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),g=d.cache=d.cache||{},i=d.count=d.count||[];return g[z](f)?(h(i,f),c?c(g[f]):g[f]):(i.length>=1e3&&delete g[i.shift()],i.push(f),g[f]=a.apply(b,e),c?c(g[f]):g[f])}return d}function j(a,b,c,d,e,f){if(null==e){var g=a-c,h=b-d;return g||h?(180+180*D.atan2(-h,-g)/H+360)%360:0}return j(a,b,e,f)-j(c,d,e,f)}function k(a){return a%360*H/180}function l(a){return 180*a/H%360}function m(a){var b=[];return a=a.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g,function(a,c,d){return d=d.split(/\s*,\s*|\s+/),"rotate"==c&&1==d.length&&d.push(0,0),"scale"==c&&(d.length>2?d=d.slice(0,2):2==d.length&&d.push(0,0),1==d.length&&d.push(d[0],0,0)),b.push("skewX"==c?["m",1,0,D.tan(k(d[0])),1,0,0]:"skewY"==c?["m",1,D.tan(k(d[0])),0,1,0,0]:[c.charAt(0)].concat(d)),a}),b}function n(a,b){var d=ab(a),e=new c.Matrix;if(d)for(var f=0,g=d.length;g>f;f++){var h,i,j,k,l,m=d[f],n=m.length,o=A(m[0]).toLowerCase(),p=m[0]!=o,q=p?e.invert():0;"t"==o&&2==n?e.translate(m[1],0):"t"==o&&3==n?p?(h=q.x(0,0),i=q.y(0,0),j=q.x(m[1],m[2]),k=q.y(m[1],m[2]),e.translate(j-h,k-i)):e.translate(m[1],m[2]):"r"==o?2==n?(l=l||b,e.rotate(m[1],l.x+l.width/2,l.y+l.height/2)):4==n&&(p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.rotate(m[1],j,k)):e.rotate(m[1],m[2],m[3])):"s"==o?2==n||3==n?(l=l||b,e.scale(m[1],m[n-1],l.x+l.width/2,l.y+l.height/2)):4==n?p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.scale(m[1],m[1],j,k)):e.scale(m[1],m[1],m[2],m[3]):5==n&&(p?(j=q.x(m[3],m[4]),k=q.y(m[3],m[4]),e.scale(m[1],m[2],j,k)):e.scale(m[1],m[2],m[3],m[4])):"m"==o&&7==n&&e.add(m[1],m[2],m[3],m[4],m[5],m[6])}return e}function o(a){var b=a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||a.node.parentNode&&w(a.node.parentNode)||c.select("svg")||c(0,0),d=b.select("defs"),e=null==d?!1:d.node;return e||(e=u("defs",b.node).node),e}function p(a){return a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||c.select("svg")}function q(a,b,c){function e(a){if(null==a)return I;if(a==+a)return a;d(j,{width:a});try{return j.getBBox().width}catch(b){return 0}}function f(a){if(null==a)return I;if(a==+a)return a;d(j,{height:a});try{return j.getBBox().height}catch(b){return 0}}function g(d,e){null==b?i[d]=e(a.attr(d)||0):d==b&&(i=e(null==c?a.attr(d)||0:c))}var h=p(a).node,i={},j=h.querySelector(".svg---mgr");switch(j||(j=d("rect"),d(j,{x:-9e9,y:-9e9,width:10,height:10,"class":"svg---mgr",fill:"none"}),h.appendChild(j)),a.type){case"rect":g("rx",e),g("ry",f);case"image":g("width",e),g("height",f);case"text":g("x",e),g("y",f);break;case"circle":g("cx",e),g("cy",f),g("r",e);break;case"ellipse":g("cx",e),g("cy",f),g("rx",e),g("ry",f);break;case"line":g("x1",e),g("x2",e),g("y1",f),g("y2",f);break;case"marker":g("refX",e),g("markerWidth",e),g("refY",f),g("markerHeight",f);break;case"radialGradient":g("fx",e),g("fy",f);break;case"tspan":g("dx",e),g("dy",f);break;default:g(b,e)}return h.removeChild(j),i}function r(a){e(a,"array")||(a=Array.prototype.slice.call(arguments,0));for(var b=0,c=0,d=this.node;this[b];)delete this[b++];for(b=0;b<a.length;b++)"set"==a[b].type?a[b].forEach(function(a){d.appendChild(a.node)}):d.appendChild(a[b].node);var f=d.childNodes;for(b=0;b<f.length;b++)this[c++]=w(f[b]);return this}function s(a){if(a.snap in V)return V[a.snap];var b;try{b=a.ownerSVGElement}catch(c){}this.node=a,b&&(this.paper=new v(b)),this.type=a.tagName||a.nodeName;var d=this.id=S(this);if(this.anims={},this._={transform:[]},a.snap=d,V[d]=this,"g"==this.type&&(this.add=r),this.type in{g:1,mask:1,pattern:1,symbol:1})for(var e in v.prototype)v.prototype[z](e)&&(this[e]=v.prototype[e])}function t(a){this.node=a}function u(a,b){var c=d(a);b.appendChild(c);var e=w(c);return e}function v(a,b){var c,e,f,g=v.prototype;if(a&&"svg"==a.tagName){if(a.snap in V)return V[a.snap];var h=a.ownerDocument;c=new s(a),e=a.getElementsByTagName("desc")[0],f=a.getElementsByTagName("defs")[0],e||(e=d("desc"),e.appendChild(h.createTextNode("Created with Snap")),c.node.appendChild(e)),f||(f=d("defs"),c.node.appendChild(f)),c.defs=f;for(var i in g)g[z](i)&&(c[i]=g[i]);c.paper=c.root=c}else c=u("svg",y.doc.body),d(c.node,{height:b,version:1.1,width:a,xmlns:U});return c}function w(a){return a?a instanceof s||a instanceof t?a:a.tagName&&"svg"==a.tagName.toLowerCase()?new v(a):a.tagName&&"object"==a.tagName.toLowerCase()&&"image/svg+xml"==a.type?new v(a.contentDocument.getElementsByTagName("svg")[0]):new s(a):a}function x(a,b){for(var c=0,d=a.length;d>c;c++){var e={type:a[c].type,attr:a[c].attr()},f=a[c].children();b.push(e),f.length&&x(f,e.childNodes=[])}}c.version="0.4.0",c.toString=function(){return"Snap v"+this.version},c._={};var y={win:a.window,doc:a.window.document};c._.glob=y;{var z="hasOwnProperty",A=String,B=parseFloat,C=parseInt,D=Math,E=D.max,F=D.min,G=D.abs,H=(D.pow,D.PI),I=(D.round,""),J=Object.prototype.toString,K=/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,L=(c._.separator=/[,\s]+/,/[\s]*,[\s]*/),M={hs:1,rg:1},N=/([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,O=/([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,P=/(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/gi,Q=0,R="S"+(+new Date).toString(36),S=function(a){return(a&&a.type?a.type:I)+R+(Q++).toString(36)},T="http://www.w3.org/1999/xlink",U="http://www.w3.org/2000/svg",V={};c.url=function(a){return"url('#"+a+"')"}}c._.$=d,c._.id=S,c.format=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return A(b).replace(a,function(a,b){return c(a,b,d)})}}(),c._.clone=f,c._.cacher=i,c.rad=k,c.deg=l,c.sin=function(a){return D.sin(c.rad(a))},c.tan=function(a){return D.tan(c.rad(a))},c.cos=function(a){return D.cos(c.rad(a))},c.asin=function(a){return c.deg(D.asin(a))},c.acos=function(a){return c.deg(D.acos(a))},c.atan=function(a){return c.deg(D.atan(a))},c.atan2=function(a){return c.deg(D.atan2(a))},c.angle=j,c.len=function(a,b,d,e){return Math.sqrt(c.len2(a,b,d,e))},c.len2=function(a,b,c,d){return(a-c)*(a-c)+(b-d)*(b-d)},c.closestPoint=function(a,b,c){function d(a){var d=a.x-b,e=a.y-c;return d*d+e*e}for(var e,f,g,h,i=a.node,j=i.getTotalLength(),k=j/i.pathSegList.numberOfItems*.125,l=1/0,m=0;j>=m;m+=k)(h=d(g=i.getPointAtLength(m)))<l&&(e=g,f=m,l=h);for(k*=.5;k>.5;){var n,o,p,q,r,s;(p=f-k)>=0&&(r=d(n=i.getPointAtLength(p)))<l?(e=n,f=p,l=r):(q=f+k)<=j&&(s=d(o=i.getPointAtLength(q)))<l?(e=o,f=q,l=s):k*=.5}return e={x:e.x,y:e.y,length:f,distance:Math.sqrt(l)}},c.is=e,c.snapTo=function(a,b,c){if(c=e(c,"finite")?c:10,e(a,"array")){for(var d=a.length;d--;)if(G(a[d]-b)<=c)return a[d]}else{a=+a;var f=b%a;if(c>f)return b-f;if(f>a-c)return b-f+a}return b},c.getRGB=i(function(a){if(!a||(a=A(a)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};if("none"==a)return{r:-1,g:-1,b:-1,hex:"none",toString:Z};if(!(M[z](a.toLowerCase().substring(0,2))||"#"==a.charAt())&&(a=W(a)),!a)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};var b,d,f,g,h,i,j=a.match(K);return j?(j[2]&&(f=C(j[2].substring(5),16),d=C(j[2].substring(3,5),16),b=C(j[2].substring(1,3),16)),j[3]&&(f=C((h=j[3].charAt(3))+h,16),d=C((h=j[3].charAt(2))+h,16),b=C((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=B(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),f=B(i[2]),"%"==i[2].slice(-1)&&(f*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100)),j[5]?(i=j[5].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsb2rgb(b,d,f,g)):j[6]?(i=j[6].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsl2rgb(b,d,f,g)):(b=F(D.round(b),255),d=F(D.round(d),255),f=F(D.round(f),255),g=F(E(g,0),1),j={r:b,g:d,b:f,toString:Z},j.hex="#"+(16777216|f|d<<8|b<<16).toString(16).slice(1),j.opacity=e(g,"finite")?g:1,j)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z}},c),c.hsb=i(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=i(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=i(function(a,b,c,d){if(e(d,"finite")){var f=D.round;return"rgba("+[f(a),f(b),f(c),+d.toFixed(2)]+")"}return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)});var W=function(a){var b=y.doc.getElementsByTagName("head")[0]||y.doc.getElementsByTagName("svg")[0],c="rgb(255, 0, 0)";return(W=i(function(a){if("red"==a.toLowerCase())return c;b.style.color=c,b.style.color=a;var d=y.doc.defaultView.getComputedStyle(b,I).getPropertyValue("color");return d==c?null:d}))(a)},X=function(){return"hsb("+[this.h,this.s,this.b]+")"},Y=function(){return"hsl("+[this.h,this.s,this.l]+")"},Z=function(){return 1==this.opacity||null==this.opacity?this.hex:"rgba("+[this.r,this.g,this.b,this.opacity]+")"},$=function(a,b,d){if(null==b&&e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&e(a,string)){var f=c.getRGB(a);a=f.r,b=f.g,d=f.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},_=function(a,b,d,f){a=D.round(255*a),b=D.round(255*b),d=D.round(255*d);var g={r:a,g:b,b:d,opacity:e(f,"finite")?f:1,hex:c.rgb(a,b,d),toString:Z};return e(f,"finite")&&(g.opacity=f),g};c.color=function(a){var b;return e(a,"object")&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):e(a,"object")&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):(e(a,"string")&&(a=c.getRGB(a)),e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&!("error"in a)?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:"none"},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1,a.error=1)),a.toString=Z,a},c.hsb2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,d=a.o,a=a.h),a*=360;var f,g,h,i,j;return a=a%360/60,j=c*b,i=j*(1-G(a%2-1)),f=g=h=c-j,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.hsl2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var f,g,h,i,j;return a=a%360/60,j=2*b*(.5>c?c:1-c),i=j*(1-G(a%2-1)),f=g=h=c-j/2,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.rgb2hsb=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=E(a,b,c),g=f-F(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:X}},c.rgb2hsl=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=E(a,b,c),h=F(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:Y}},c.parsePathString=function(a){if(!a)return null;var b=c.path(a);if(b.arr)return c.path.clone(b.arr);var d={a:7,c:6,o:2,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,u:3,z:0},f=[];return e(a,"array")&&e(a[0],"array")&&(f=c.path.clone(a)),f.length||A(a).replace(N,function(a,b,c){var e=[],g=b.toLowerCase();if(c.replace(P,function(a,b){b&&e.push(+b)}),"m"==g&&e.length>2&&(f.push([b].concat(e.splice(0,2))),g="l",b="m"==b?"l":"L"),"o"==g&&1==e.length&&f.push([b,e[0]]),"r"==g)f.push([b].concat(e));else for(;e.length>=d[g]&&(f.push([b].concat(e.splice(0,d[g]))),d[g]););}),f.toString=c.path.toString,b.arr=c.path.clone(f),f};var ab=c.parseTransformString=function(a){if(!a)return null;var b=[];return e(a,"array")&&e(a[0],"array")&&(b=c.path.clone(a)),b.length||A(a).replace(O,function(a,c,d){{var e=[];c.toLowerCase()}d.replace(P,function(a,b){b&&e.push(+b)}),b.push([c].concat(e))}),b.toString=c.path.toString,b};c._.svgTransform2string=m,c._.rgTransform=/^[a-z][\s]*-?\.?\d/i,c._.transform2matrix=n,c._unit2px=q;y.doc.contains||y.doc.compareDocumentPosition?function(a,b){var c=9==a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a==d||!(!d||1!=d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b;)if(b=b.parentNode,b==a)return!0;return!1};c._.getSomeDefs=o,c._.getSomeSVG=p,c.select=function(a){return a=A(a).replace(/([^\\]):/g,"$1\\:"),w(y.doc.querySelector(a))},c.selectAll=function(a){for(var b=y.doc.querySelectorAll(a),d=(c.set||Array)(),e=0;e<b.length;e++)d.push(w(b[e]));return d},setInterval(function(){for(var a in V)if(V[z](a)){var b=V[a],c=b.node;("svg"!=b.type&&!c.ownerSVGElement||"svg"==b.type&&(!c.parentNode||"ownerSVGElement"in c.parentNode&&!c.ownerSVGElement))&&delete V[a]}},1e4),s.prototype.attr=function(a,c){var d=this,f=d.node;if(!a){if(1!=f.nodeType)return{text:f.nodeValue};for(var g=f.attributes,h={},i=0,j=g.length;j>i;i++)h[g[i].nodeName]=g[i].nodeValue;return h}if(e(a,"string")){if(!(arguments.length>1))return b("snap.util.getattr."+a,d).firstDefined();var k={};k[a]=c,a=k}for(var l in a)a[z](l)&&b("snap.util.attr."+l,d,a[l]);return d},c.parse=function(a){var b=y.doc.createDocumentFragment(),c=!0,d=y.doc.createElement("div");if(a=A(a),a.match(/^\s*<\s*svg(?:\s|>)/)||(a="<svg>"+a+"</svg>",c=!1),d.innerHTML=a,a=d.getElementsByTagName("svg")[0])if(c)b=a;else for(;a.firstChild;)b.appendChild(a.firstChild);return new t(b)},c.fragment=function(){for(var a=Array.prototype.slice.call(arguments,0),b=y.doc.createDocumentFragment(),d=0,e=a.length;e>d;d++){var f=a[d];f.node&&f.node.nodeType&&b.appendChild(f.node),f.nodeType&&b.appendChild(f),"string"==typeof f&&b.appendChild(c.parse(f).node)}return new t(b)},c._.make=u,c._.wrap=w,v.prototype.el=function(a,b){var c=u(a,this.node);return b&&c.attr(b),c},s.prototype.children=function(){for(var a=[],b=this.node.childNodes,d=0,e=b.length;e>d;d++)a[d]=c(b[d]);return a},s.prototype.toJSON=function(){var a=[];return x([this],a),a[0]},b.on("snap.util.getattr",function(){var a=b.nt();a=a.substring(a.lastIndexOf(".")+1);var c=a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});return bb[z](c)?this.node.ownerDocument.defaultView.getComputedStyle(this.node,null).getPropertyValue(c):d(this.node,a)});var bb={"alignment-baseline":0,"baseline-shift":0,clip:0,"clip-path":0,"clip-rule":0,color:0,"color-interpolation":0,"color-interpolation-filters":0,"color-profile":0,"color-rendering":0,cursor:0,direction:0,display:0,"dominant-baseline":0,"enable-background":0,fill:0,"fill-opacity":0,"fill-rule":0,filter:0,"flood-color":0,"flood-opacity":0,font:0,"font-family":0,"font-size":0,"font-size-adjust":0,"font-stretch":0,"font-style":0,"font-variant":0,"font-weight":0,"glyph-orientation-horizontal":0,"glyph-orientation-vertical":0,"image-rendering":0,kerning:0,"letter-spacing":0,"lighting-color":0,marker:0,"marker-end":0,"marker-mid":0,"marker-start":0,mask:0,opacity:0,overflow:0,"pointer-events":0,"shape-rendering":0,"stop-color":0,"stop-opacity":0,stroke:0,"stroke-dasharray":0,"stroke-dashoffset":0,"stroke-linecap":0,"stroke-linejoin":0,"stroke-miterlimit":0,"stroke-opacity":0,"stroke-width":0,"text-anchor":0,"text-decoration":0,"text-rendering":0,"unicode-bidi":0,visibility:0,"word-spacing":0,"writing-mode":0};b.on("snap.util.attr",function(a){var c=b.nt(),e={};c=c.substring(c.lastIndexOf(".")+1),e[c]=a;var f=c.replace(/-(\w)/gi,function(a,b){return b.toUpperCase()}),g=c.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});bb[z](g)?this.node.style[f]=null==a?I:a:d(this.node,e)}),function(){}(v.prototype),c.ajax=function(a,c,d,f){var g=new XMLHttpRequest,h=S();if(g){if(e(c,"function"))f=d,d=c,c=null;else if(e(c,"object")){var i=[];for(var j in c)c.hasOwnProperty(j)&&i.push(encodeURIComponent(j)+"="+encodeURIComponent(c[j]));c=i.join("&")}return g.open(c?"POST":"GET",a,!0),c&&(g.setRequestHeader("X-Requested-With","XMLHttpRequest"),g.setRequestHeader("Content-type","application/x-www-form-urlencoded")),d&&(b.once("snap.ajax."+h+".0",d),b.once("snap.ajax."+h+".200",d),b.once("snap.ajax."+h+".304",d)),g.onreadystatechange=function(){4==g.readyState&&b("snap.ajax."+h+"."+g.status,f,g)},4==g.readyState?g:(g.send(c),g)}},c.load=function(a,b,d){c.ajax(a,function(a){var e=c.parse(a.responseText);d?b.call(d,e):b(e)})};var cb=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,h=e.clientLeft||d.clientLeft||0,i=b.top+(g.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(g.win.pageXOffset||e.scrollLeft||d.scrollLeft)-h;return{y:i,x:j}};return c.getElementByPoint=function(a,b){var c=this,d=(c.canvas,y.doc.elementFromPoint(a,b));if(y.win.opera&&"svg"==d.tagName){var e=cb(d),f=d.createSVGRect();f.x=a-e.x,f.y=b-e.y,f.width=f.height=1;var g=d.getIntersectionList(f,null);g.length&&(d=g[g.length-1])}return d?w(d):null},c.plugin=function(a){a(c,s,v,y,t)},y.win.Snap=c,c}(a||this);return d.plugin(function(d,e,f,g,h){function i(a,b){if(null==b){var c=!0;if(b=a.node.getAttribute("linearGradient"==a.type||"radialGradient"==a.type?"gradientTransform":"pattern"==a.type?"patternTransform":"transform"),!b)return new d.Matrix;b=d._.svgTransform2string(b)}else b=d._.rgTransform.test(b)?o(b).replace(/\.{3}|\u2026/g,a._.transform||""):d._.svgTransform2string(b),n(b,"array")&&(b=d.path?d.path.toString.call(b):o(b)),a._.transform=b;var e=d._.transform2matrix(b,a.getBBox(1));return c?e:void(a.matrix=e)}function j(a){function b(a,b){var c=q(a.node,b);c=c&&c.match(f),c=c&&c[2],c&&"#"==c.charAt()&&(c=c.substring(1),c&&(h[c]=(h[c]||[]).concat(function(c){var d={};d[b]=URL(c),q(a.node,d)})))}function c(a){var b=q(a.node,"xlink:href");b&&"#"==b.charAt()&&(b=b.substring(1),b&&(h[b]=(h[b]||[]).concat(function(b){a.attr("xlink:href","#"+b)})))}for(var d,e=a.selectAll("*"),f=/^\s*url\(("|'|)(.*)\1\)\s*$/,g=[],h={},i=0,j=e.length;j>i;i++){d=e[i],b(d,"fill"),b(d,"stroke"),b(d,"filter"),b(d,"mask"),b(d,"clip-path"),c(d);var k=q(d.node,"id");k&&(q(d.node,{id:d.id}),g.push({old:k,id:d.id}))}for(i=0,j=g.length;j>i;i++){var l=h[g[i].old];if(l)for(var m=0,n=l.length;n>m;m++)l[m](g[i].id)}}function k(a,b,c){return function(d){var e=d.slice(a,b);return 1==e.length&&(e=e[0]),c?c(e):e}}function l(a){return function(){var b=a?"<"+this.type:"",c=this.node.attributes,d=this.node.childNodes;if(a)for(var e=0,f=c.length;f>e;e++)b+=" "+c[e].name+'="'+c[e].value.replace(/"/g,'\\"')+'"';if(d.length){for(a&&(b+=">"),e=0,f=d.length;f>e;e++)3==d[e].nodeType?b+=d[e].nodeValue:1==d[e].nodeType&&(b+=u(d[e]).toString());a&&(b+="</"+this.type+">")}else a&&(b+="/>");return b}}var m=e.prototype,n=d.is,o=String,p=d._unit2px,q=d._.$,r=d._.make,s=d._.getSomeDefs,t="hasOwnProperty",u=d._.wrap;m.getBBox=function(a){if(!d.Matrix||!d.path)return this.node.getBBox();var b=this,c=new d.Matrix;if(b.removed)return d._.box();for(;"use"==b.type;)if(a||(c=c.add(b.transform().localMatrix.translate(b.attr("x")||0,b.attr("y")||0))),b.original)b=b.original;else{var e=b.attr("xlink:href");b=b.original=b.node.ownerDocument.getElementById(e.substring(e.indexOf("#")+1))}var f=b._,g=d.path.get[b.type]||d.path.get.deflt;try{return a?(f.bboxwt=g?d.path.getBBox(b.realPath=g(b)):d._.box(b.node.getBBox()),d._.box(f.bboxwt)):(b.realPath=g(b),b.matrix=b.transform().localMatrix,f.bbox=d.path.getBBox(d.path.map(b.realPath,c.add(b.matrix))),d._.box(f.bbox))}catch(h){return d._.box()}};var v=function(){return this.string};m.transform=function(a){var b=this._;if(null==a){for(var c,e=this,f=new d.Matrix(this.node.getCTM()),g=i(this),h=[g],j=new d.Matrix,k=g.toTransformString(),l=o(g)==o(this.matrix)?o(b.transform):k;"svg"!=e.type&&(e=e.parent());)h.push(i(e));for(c=h.length;c--;)j.add(h[c]);return{string:l,globalMatrix:f,totalMatrix:j,localMatrix:g,diffMatrix:f.clone().add(g.invert()),global:f.toTransformString(),total:j.toTransformString(),local:k,toString:v}}return a instanceof d.Matrix?(this.matrix=a,this._.transform=a.toTransformString()):i(this,a),this.node&&("linearGradient"==this.type||"radialGradient"==this.type?q(this.node,{gradientTransform:this.matrix}):"pattern"==this.type?q(this.node,{patternTransform:this.matrix}):q(this.node,{transform:this.matrix})),this},m.parent=function(){return u(this.node.parentNode)},m.append=m.add=function(a){if(a){if("set"==a.type){var b=this;return a.forEach(function(a){b.add(a)}),this}a=u(a),this.node.appendChild(a.node),a.paper=this.paper}return this},m.appendTo=function(a){return a&&(a=u(a),a.append(this)),this},m.prepend=function(a){if(a){if("set"==a.type){var b,c=this;return a.forEach(function(a){b?b.after(a):c.prepend(a),b=a}),this}a=u(a);var d=a.parent();this.node.insertBefore(a.node,this.node.firstChild),this.add&&this.add(),a.paper=this.paper,this.parent()&&this.parent().add(),d&&d.add()}return this},m.prependTo=function(a){return a=u(a),a.prepend(this),this},m.before=function(a){if("set"==a.type){var b=this;return a.forEach(function(a){var c=a.parent();b.node.parentNode.insertBefore(a.node,b.node),c&&c.add()}),this.parent().add(),this}a=u(a);var c=a.parent();return this.node.parentNode.insertBefore(a.node,this.node),this.parent()&&this.parent().add(),c&&c.add(),a.paper=this.paper,this},m.after=function(a){a=u(a);var b=a.parent();return this.node.nextSibling?this.node.parentNode.insertBefore(a.node,this.node.nextSibling):this.node.parentNode.appendChild(a.node),this.parent()&&this.parent().add(),b&&b.add(),a.paper=this.paper,this},m.insertBefore=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.insertAfter=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node.nextSibling),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.remove=function(){var a=this.parent();return this.node.parentNode&&this.node.parentNode.removeChild(this.node),delete this.paper,this.removed=!0,a&&a.add(),this},m.select=function(a){return u(this.node.querySelector(a))},m.selectAll=function(a){for(var b=this.node.querySelectorAll(a),c=(d.set||Array)(),e=0;e<b.length;e++)c.push(u(b[e]));return c},m.asPX=function(a,b){return null==b&&(b=this.attr(a)),+p(this,a,b)},m.use=function(){var a,b=this.node.id;return b||(b=this.id,q(this.node,{id:b})),a="linearGradient"==this.type||"radialGradient"==this.type||"pattern"==this.type?r(this.type,this.node.parentNode):r("use",this.node.parentNode),q(a.node,{"xlink:href":"#"+b}),a.original=this,a},m.clone=function(){var a=u(this.node.cloneNode(!0));return q(a.node,"id")&&q(a.node,{id:a.id}),j(a),a.insertAfter(this),a},m.toDefs=function(){var a=s(this);return a.appendChild(this.node),this},m.pattern=m.toPattern=function(a,b,c,d){var e=r("pattern",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,a=a.x),q(e.node,{x:a,y:b,width:c,height:d,patternUnits:"userSpaceOnUse",id:e.id,viewBox:[a,b,c,d].join(" ")}),e.node.appendChild(this.node),e},m.marker=function(a,b,c,d,e,f){var g=r("marker",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,e=a.refX||a.cx,f=a.refY||a.cy,a=a.x),q(g.node,{viewBox:[a,b,c,d].join(" "),markerWidth:c,markerHeight:d,orient:"auto",refX:e||0,refY:f||0,id:g.id}),g.node.appendChild(this.node),g};var w=function(a,b,d,e){"function"!=typeof d||d.length||(e=d,d=c.linear),this.attr=a,this.dur=b,d&&(this.easing=d),e&&(this.callback=e)};d._.Animation=w,d.animation=function(a,b,c,d){return new w(a,b,c,d)},m.inAnim=function(){var a=this,b=[];for(var c in a.anims)a.anims[t](c)&&!function(a){b.push({anim:new w(a._attrs,a.dur,a.easing,a._callback),mina:a,curStatus:a.status(),status:function(b){return a.status(b)},stop:function(){a.stop()}})}(a.anims[c]);return b},d.animate=function(a,d,e,f,g,h){"function"!=typeof g||g.length||(h=g,g=c.linear);var i=c.time(),j=c(a,d,i,i+f,c.time,e,g);return h&&b.once("mina.finish."+j.id,h),j},m.stop=function(){for(var a=this.inAnim(),b=0,c=a.length;c>b;b++)a[b].stop();return this},m.animate=function(a,d,e,f){"function"!=typeof e||e.length||(f=e,e=c.linear),a instanceof w&&(f=a.callback,e=a.easing,d=a.dur,a=a.attr);var g,h,i,j,l=[],m=[],p={},q=this;for(var r in a)if(a[t](r)){q.equal?(j=q.equal(r,o(a[r])),g=j.from,h=j.to,i=j.f):(g=+q.attr(r),h=+a[r]);var s=n(g,"array")?g.length:1;p[r]=k(l.length,l.length+s,i),l=l.concat(g),m=m.concat(h)}var u=c.time(),v=c(l,m,u,u+d,c.time,function(a){var b={};for(var c in p)p[t](c)&&(b[c]=p[c](a));q.attr(b)},e);return q.anims[v.id]=v,v._attrs=a,v._callback=f,b("snap.animcreated."+q.id,v),b.once("mina.finish."+v.id,function(){delete q.anims[v.id],f&&f.call(q)}),b.once("mina.stop."+v.id,function(){delete q.anims[v.id]}),q};var x={};m.data=function(a,c){var e=x[this.id]=x[this.id]||{};if(0==arguments.length)return b("snap.data.get."+this.id,this,e,null),e; +if(1==arguments.length){if(d.is(a,"object")){for(var f in a)a[t](f)&&this.data(f,a[f]);return this}return b("snap.data.get."+this.id,this,e[a],a),e[a]}return e[a]=c,b("snap.data.set."+this.id,this,c,a),this},m.removeData=function(a){return null==a?x[this.id]={}:x[this.id]&&delete x[this.id][a],this},m.outerSVG=m.toString=l(1),m.innerSVG=l(),m.toDataURL=function(){if(a&&a.btoa){var b=this.getBBox(),c=d.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>',{x:+b.x.toFixed(3),y:+b.y.toFixed(3),width:+b.width.toFixed(3),height:+b.height.toFixed(3),contents:this.outerSVG()});return"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(c)))}},h.prototype.select=m.select,h.prototype.selectAll=m.selectAll}),d.plugin(function(a){function b(a,b,d,e,f,g){return null==b&&"[object SVGMatrix]"==c.call(a)?(this.a=a.a,this.b=a.b,this.c=a.c,this.d=a.d,this.e=a.e,void(this.f=a.f)):void(null!=a?(this.a=+a,this.b=+b,this.c=+d,this.d=+e,this.e=+f,this.f=+g):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0))}var c=Object.prototype.toString,d=String,e=Math,f="";!function(c){function g(a){return a[0]*a[0]+a[1]*a[1]}function h(a){var b=e.sqrt(g(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}c.add=function(a,c,d,e,f,g){var h,i,j,k,l=[[],[],[]],m=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],n=[[a,d,f],[c,e,g],[0,0,1]];for(a&&a instanceof b&&(n=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),h=0;3>h;h++)for(i=0;3>i;i++){for(k=0,j=0;3>j;j++)k+=m[h][j]*n[j][i];l[h][i]=k}return this.a=l[0][0],this.b=l[1][0],this.c=l[0][1],this.d=l[1][1],this.e=l[0][2],this.f=l[1][2],this},c.invert=function(){var a=this,c=a.a*a.d-a.b*a.c;return new b(a.d/c,-a.b/c,-a.c/c,a.a/c,(a.c*a.f-a.d*a.e)/c,(a.b*a.e-a.a*a.f)/c)},c.clone=function(){return new b(this.a,this.b,this.c,this.d,this.e,this.f)},c.translate=function(a,b){return this.add(1,0,0,1,a,b)},c.scale=function(a,b,c,d){return null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d),this},c.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var f=+e.cos(b).toFixed(9),g=+e.sin(b).toFixed(9);return this.add(f,g,-g,f,c,d),this.add(1,0,0,1,-c,-d)},c.x=function(a,b){return a*this.a+b*this.c+this.e},c.y=function(a,b){return a*this.b+b*this.d+this.f},c.get=function(a){return+this[d.fromCharCode(97+a)].toFixed(4)},c.toString=function(){return"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")"},c.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},c.determinant=function(){return this.a*this.d-this.b*this.c},c.split=function(){var b={};b.dx=this.e,b.dy=this.f;var c=[[this.a,this.c],[this.b,this.d]];b.scalex=e.sqrt(g(c[0])),h(c[0]),b.shear=c[0][0]*c[1][0]+c[0][1]*c[1][1],c[1]=[c[1][0]-c[0][0]*b.shear,c[1][1]-c[0][1]*b.shear],b.scaley=e.sqrt(g(c[1])),h(c[1]),b.shear/=b.scaley,this.determinant()<0&&(b.scalex=-b.scalex);var d=-c[0][1],f=c[1][1];return 0>f?(b.rotate=a.deg(e.acos(f)),0>d&&(b.rotate=360-b.rotate)):b.rotate=a.deg(e.asin(d)),b.isSimple=!(+b.shear.toFixed(9)||b.scalex.toFixed(9)!=b.scaley.toFixed(9)&&b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate,b},c.toTransformString=function(a){var b=a||this.split();return+b.shear.toFixed(9)?"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]:(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[+b.dx.toFixed(4),+b.dy.toFixed(4)]:f)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:f)+(b.rotate?"r"+[+b.rotate.toFixed(4),0,0]:f))}}(b.prototype),a.Matrix=b,a.matrix=function(a,c,d,e,f,g){return new b(a,c,d,e,f,g)}}),d.plugin(function(a,c,d,e,f){function g(d){return function(e){if(b.stop(),e instanceof f&&1==e.node.childNodes.length&&("radialGradient"==e.node.firstChild.tagName||"linearGradient"==e.node.firstChild.tagName||"pattern"==e.node.firstChild.tagName)&&(e=e.node.firstChild,n(this).appendChild(e),e=l(e)),e instanceof c)if("radialGradient"==e.type||"linearGradient"==e.type||"pattern"==e.type){e.node.id||p(e.node,{id:e.id});var g=q(e.node.id)}else g=e.attr(d);else if(g=a.color(e),g.error){var h=a(n(this).ownerSVGElement).gradient(e);h?(h.node.id||p(h.node,{id:h.id}),g=q(h.node.id)):g=e}else g=r(g);var i={};i[d]=g,p(this.node,i),this.node.style[d]=t}}function h(a){b.stop(),a==+a&&(a+="px"),this.node.style.fontSize=a}function i(a){for(var b=[],c=a.childNodes,d=0,e=c.length;e>d;d++){var f=c[d];3==f.nodeType&&b.push(f.nodeValue),"tspan"==f.tagName&&b.push(1==f.childNodes.length&&3==f.firstChild.nodeType?f.firstChild.nodeValue:i(f))}return b}function j(){return b.stop(),this.node.style.fontSize}var k=a._.make,l=a._.wrap,m=a.is,n=a._.getSomeDefs,o=/^url\(#?([^)]+)\)$/,p=a._.$,q=a.url,r=String,s=a._.separator,t="";b.on("snap.util.attr.mask",function(a){if(a instanceof c||a instanceof f){if(b.stop(),a instanceof f&&1==a.node.childNodes.length&&(a=a.node.firstChild,n(this).appendChild(a),a=l(a)),"mask"==a.type)var d=a;else d=k("mask",n(this)),d.node.appendChild(a.node);!d.node.id&&p(d.node,{id:d.id}),p(this.node,{mask:q(d.id)})}}),function(a){b.on("snap.util.attr.clip",a),b.on("snap.util.attr.clip-path",a),b.on("snap.util.attr.clipPath",a)}(function(a){if(a instanceof c||a instanceof f){if(b.stop(),"clipPath"==a.type)var d=a;else d=k("clipPath",n(this)),d.node.appendChild(a.node),!d.node.id&&p(d.node,{id:d.id});p(this.node,{"clip-path":q(d.node.id||d.id)})}}),b.on("snap.util.attr.fill",g("fill")),b.on("snap.util.attr.stroke",g("stroke"));var u=/^([lr])(?:\(([^)]*)\))?(.*)$/i;b.on("snap.util.grad.parse",function(a){a=r(a);var b=a.match(u);if(!b)return null;var c=b[1],d=b[2],e=b[3];return d=d.split(/\s*,\s*/).map(function(a){return+a==a?+a:a}),1==d.length&&0==d[0]&&(d=[]),e=e.split("-"),e=e.map(function(a){a=a.split(":");var b={color:a[0]};return a[1]&&(b.offset=parseFloat(a[1])),b}),{type:c,params:d,stops:e}}),b.on("snap.util.attr.d",function(c){b.stop(),m(c,"array")&&m(c[0],"array")&&(c=a.path.toString.call(c)),c=r(c),c.match(/[ruo]/i)&&(c=a.path.toAbsolute(c)),p(this.node,{d:c})})(-1),b.on("snap.util.attr.#text",function(a){b.stop(),a=r(a);for(var c=e.doc.createTextNode(a);this.node.firstChild;)this.node.removeChild(this.node.firstChild);this.node.appendChild(c)})(-1),b.on("snap.util.attr.path",function(a){b.stop(),this.attr({d:a})})(-1),b.on("snap.util.attr.class",function(a){b.stop(),this.node.className.baseVal=a})(-1),b.on("snap.util.attr.viewBox",function(a){var c;c=m(a,"object")&&"x"in a?[a.x,a.y,a.width,a.height].join(" "):m(a,"array")?a.join(" "):a,p(this.node,{viewBox:c}),b.stop()})(-1),b.on("snap.util.attr.transform",function(a){this.transform(a),b.stop()})(-1),b.on("snap.util.attr.r",function(a){"rect"==this.type&&(b.stop(),p(this.node,{rx:a,ry:a}))})(-1),b.on("snap.util.attr.textpath",function(a){if(b.stop(),"text"==this.type){var d,e,f;if(!a&&this.textPath){for(e=this.textPath;e.node.firstChild;)this.node.appendChild(e.node.firstChild);return e.remove(),void delete this.textPath}if(m(a,"string")){var g=n(this),h=l(g.parentNode).path(a);g.appendChild(h.node),d=h.id,h.attr({id:d})}else a=l(a),a instanceof c&&(d=a.attr("id"),d||(d=a.id,a.attr({id:d})));if(d)if(e=this.textPath,f=this.node,e)e.attr({"xlink:href":"#"+d});else{for(e=p("textPath",{"xlink:href":"#"+d});f.firstChild;)e.appendChild(f.firstChild);f.appendChild(e),this.textPath=l(e)}}})(-1),b.on("snap.util.attr.text",function(a){if("text"==this.type){for(var c=this.node,d=function(a){var b=p("tspan");if(m(a,"array"))for(var c=0;c<a.length;c++)b.appendChild(d(a[c]));else b.appendChild(e.doc.createTextNode(a));return b.normalize&&b.normalize(),b};c.firstChild;)c.removeChild(c.firstChild);for(var f=d(a);f.firstChild;)c.appendChild(f.firstChild)}b.stop()})(-1),b.on("snap.util.attr.fontSize",h)(-1),b.on("snap.util.attr.font-size",h)(-1),b.on("snap.util.getattr.transform",function(){return b.stop(),this.transform()})(-1),b.on("snap.util.getattr.textpath",function(){return b.stop(),this.textPath})(-1),function(){function c(c){return function(){b.stop();var d=e.doc.defaultView.getComputedStyle(this.node,null).getPropertyValue("marker-"+c);return"none"==d?d:a(e.doc.getElementById(d.match(o)[1]))}}function d(a){return function(c){b.stop();var d="marker"+a.charAt(0).toUpperCase()+a.substring(1);if(""==c||!c)return void(this.node.style[d]="none");if("marker"==c.type){var e=c.node.id;return e||p(c.node,{id:c.id}),void(this.node.style[d]=q(e))}}}b.on("snap.util.getattr.marker-end",c("end"))(-1),b.on("snap.util.getattr.markerEnd",c("end"))(-1),b.on("snap.util.getattr.marker-start",c("start"))(-1),b.on("snap.util.getattr.markerStart",c("start"))(-1),b.on("snap.util.getattr.marker-mid",c("mid"))(-1),b.on("snap.util.getattr.markerMid",c("mid"))(-1),b.on("snap.util.attr.marker-end",d("end"))(-1),b.on("snap.util.attr.markerEnd",d("end"))(-1),b.on("snap.util.attr.marker-start",d("start"))(-1),b.on("snap.util.attr.markerStart",d("start"))(-1),b.on("snap.util.attr.marker-mid",d("mid"))(-1),b.on("snap.util.attr.markerMid",d("mid"))(-1)}(),b.on("snap.util.getattr.r",function(){return"rect"==this.type&&p(this.node,"rx")==p(this.node,"ry")?(b.stop(),p(this.node,"rx")):void 0})(-1),b.on("snap.util.getattr.text",function(){if("text"==this.type||"tspan"==this.type){b.stop();var a=i(this.node);return 1==a.length?a[0]:a}})(-1),b.on("snap.util.getattr.#text",function(){return this.node.textContent})(-1),b.on("snap.util.getattr.viewBox",function(){b.stop();var c=p(this.node,"viewBox");return c?(c=c.split(s),a._.box(+c[0],+c[1],+c[2],+c[3])):void 0})(-1),b.on("snap.util.getattr.points",function(){var a=p(this.node,"points");return b.stop(),a?a.split(s):void 0})(-1),b.on("snap.util.getattr.path",function(){var a=p(this.node,"d");return b.stop(),a})(-1),b.on("snap.util.getattr.class",function(){return this.node.className.baseVal})(-1),b.on("snap.util.getattr.fontSize",j)(-1),b.on("snap.util.getattr.font-size",j)(-1)}),d.plugin(function(a,b){var c=/\S+/g,d=String,e=b.prototype;e.addClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(h.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e||k.push(f);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.removeClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(k.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e&&k.splice(e,1);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.hasClass=function(a){var b=this.node,d=b.className.baseVal,e=d.match(c)||[];return!!~e.indexOf(a)},e.toggleClass=function(a,b){if(null!=b)return b?this.addClass(a):this.removeClass(a);var d,e,f,g,h=(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];for(d=0;f=h[d++];)e=k.indexOf(f),~e?k.splice(e,1):k.push(f);return g=k.join(" "),j!=g&&(i.className.baseVal=g),this}}),d.plugin(function(){function a(a){return a}function c(a){return function(b){return+b.toFixed(3)+a}}var d={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"/":function(a,b){return a/b},"*":function(a,b){return a*b}},e=String,f=/[a-z]+$/i,g=/^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;b.on("snap.util.attr",function(a){var c=e(a).match(g);if(c){var h=b.nt(),i=h.substring(h.lastIndexOf(".")+1),j=this.attr(i),k={};b.stop();var l=c[3]||"",m=j.match(f),n=d[c[1]];if(m&&m==l?a=n(parseFloat(j),+c[2]):(j=this.asPX(i),a=n(this.asPX(i),this.asPX(i,c[2]+l))),isNaN(j)||isNaN(a))return;k[i]=a,this.attr(k)}})(-10),b.on("snap.util.equal",function(h,i){var j=e(this.attr(h)||""),k=e(i).match(g);if(k){b.stop();var l=k[3]||"",m=j.match(f),n=d[k[1]];return m&&m==l?{from:parseFloat(j),to:n(parseFloat(j),+k[2]),f:c(m)}:(j=this.asPX(h),{from:j,to:n(j,this.asPX(h,k[2]+l)),f:a})}})(-10)}),d.plugin(function(c,d,e,f){var g=e.prototype,h=c.is;g.rect=function(a,b,c,d,e,f){var g;return null==f&&(f=e),h(a,"object")&&"[object Object]"==a?g=a:null!=a&&(g={x:a,y:b,width:c,height:d},null!=e&&(g.rx=e,g.ry=f)),this.el("rect",g)},g.circle=function(a,b,c){var d;return h(a,"object")&&"[object Object]"==a?d=a:null!=a&&(d={cx:a,cy:b,r:c}),this.el("circle",d)};var i=function(){function a(){this.parentNode.removeChild(this)}return function(b,c){var d=f.doc.createElement("img"),e=f.doc.body;d.style.cssText="position:absolute;left:-9999em;top:-9999em",d.onload=function(){c.call(d),d.onload=d.onerror=null,e.removeChild(d)},d.onerror=a,e.appendChild(d),d.src=b}}();g.image=function(a,b,d,e,f){var g=this.el("image");if(h(a,"object")&&"src"in a)g.attr(a);else if(null!=a){var j={"xlink:href":a,preserveAspectRatio:"none"};null!=b&&null!=d&&(j.x=b,j.y=d),null!=e&&null!=f?(j.width=e,j.height=f):i(a,function(){c._.$(g.node,{width:this.offsetWidth,height:this.offsetHeight})}),c._.$(g.node,j)}return g},g.ellipse=function(a,b,c,d){var e;return h(a,"object")&&"[object Object]"==a?e=a:null!=a&&(e={cx:a,cy:b,rx:c,ry:d}),this.el("ellipse",e)},g.path=function(a){var b;return h(a,"object")&&!h(a,"array")?b=a:a&&(b={d:a}),this.el("path",b)},g.group=g.g=function(a){var b=this.el("g");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.svg=function(a,b,c,d,e,f,g,i){var j={};return h(a,"object")&&null==b?j=a:(null!=a&&(j.x=a),null!=b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),null!=e&&null!=f&&null!=g&&null!=i&&(j.viewBox=[e,f,g,i])),this.el("svg",j)},g.mask=function(a){var b=this.el("mask");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.ptrn=function(a,b,c,d,e,f,g,i){if(h(a,"object"))var j=a;else j={patternUnits:"userSpaceOnUse"},a&&(j.x=a),b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),j.viewBox=null!=e&&null!=f&&null!=g&&null!=i?[e,f,g,i]:[a||0,b||0,c||0,d||0];return this.el("pattern",j)},g.use=function(a){return null!=a?(a instanceof d&&(a.attr("id")||a.attr({id:c._.id(a)}),a=a.attr("id")),"#"==String(a).charAt()&&(a=a.substring(1)),this.el("use",{"xlink:href":"#"+a})):d.prototype.use.call(this)},g.symbol=function(a,b,c,d){var e={};return null!=a&&null!=b&&null!=c&&null!=d&&(e.viewBox=[a,b,c,d]),this.el("symbol",e)},g.text=function(a,b,c){var d={};return h(a,"object")?d=a:null!=a&&(d={x:a,y:b,text:c||""}),this.el("text",d)},g.line=function(a,b,c,d){var e={};return h(a,"object")?e=a:null!=a&&(e={x1:a,x2:c,y1:b,y2:d}),this.el("line",e)},g.polyline=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polyline",b)},g.polygon=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polygon",b)},function(){function d(){return this.selectAll("stop")}function e(a,b){var d=k("stop"),e={offset:+b+"%"};return a=c.color(a),e["stop-color"]=a.hex,a.opacity<1&&(e["stop-opacity"]=a.opacity),k(d,e),this.node.appendChild(d),this}function f(){if("linearGradient"==this.type){var a=k(this.node,"x1")||0,b=k(this.node,"x2")||1,d=k(this.node,"y1")||0,e=k(this.node,"y2")||0;return c._.box(a,d,math.abs(b-a),math.abs(e-d))}var f=this.node.cx||.5,g=this.node.cy||.5,h=this.node.r||0;return c._.box(f-h,g-h,2*h,2*h)}function h(a,c){function d(a,b){for(var c=(b-l)/(a-m),d=m;a>d;d++)g[d].offset=+(+l+c*(d-m)).toFixed(2);m=a,l=b}var e,f=b("snap.util.grad.parse",null,c).firstDefined();if(!f)return null;f.params.unshift(a),e="l"==f.type.toLowerCase()?i.apply(0,f.params):j.apply(0,f.params),f.type!=f.type.toLowerCase()&&k(e.node,{gradientUnits:"userSpaceOnUse"});var g=f.stops,h=g.length,l=0,m=0;h--;for(var n=0;h>n;n++)"offset"in g[n]&&d(n,g[n].offset);for(g[h].offset=g[h].offset||100,d(h,g[h].offset),n=0;h>=n;n++){var o=g[n];e.addStop(o.color,o.offset)}return e}function i(a,b,g,h,i){var j=c._.make("linearGradient",a);return j.stops=d,j.addStop=e,j.getBBox=f,null!=b&&k(j.node,{x1:b,y1:g,x2:h,y2:i}),j}function j(a,b,g,h,i,j){var l=c._.make("radialGradient",a);return l.stops=d,l.addStop=e,l.getBBox=f,null!=b&&k(l.node,{cx:b,cy:g,r:h}),null!=i&&null!=j&&k(l.node,{fx:i,fy:j}),l}var k=c._.$;g.gradient=function(a){return h(this.defs,a)},g.gradientLinear=function(a,b,c,d){return i(this.defs,a,b,c,d)},g.gradientRadial=function(a,b,c,d,e){return j(this.defs,a,b,c,d,e)},g.toString=function(){var a,b=this.node.ownerDocument,d=b.createDocumentFragment(),e=b.createElement("div"),f=this.node.cloneNode(!0);return d.appendChild(e),e.appendChild(f),c._.$(f,{xmlns:"http://www.w3.org/2000/svg"}),a=e.innerHTML,d.removeChild(d.firstChild),a},g.toDataURL=function(){return a&&a.btoa?"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(this))):void 0},g.clear=function(){for(var a,b=this.node.firstChild;b;)a=b.nextSibling,"defs"!=b.tagName?b.parentNode.removeChild(b):g.clear.call({node:b}),b=a}}()}),d.plugin(function(a,b){function c(a){var b=c.ps=c.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[K](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]}function d(a,b,c,d){return null==a&&(a=b=c=d=0),null==b&&(b=a.y,c=a.width,d=a.height,a=a.x),{x:a,y:b,width:c,w:c,height:d,h:d,x2:a+c,y2:b+d,cx:a+c/2,cy:b+d/2,r1:N.min(c,d)/2,r2:N.max(c,d)/2,r0:N.sqrt(c*c+d*d)/2,path:w(a,b,c,d),vb:[a,b,c,d].join(" ")}}function e(){return this.join(",").replace(L,"$1")}function f(a){var b=J(a);return b.toString=e,b}function g(a,b,c,d,e,f,g,h,j){return null==j?n(a,b,c,d,e,f,g,h):i(a,b,c,d,e,f,g,h,o(a,b,c,d,e,f,g,h,j))}function h(c,d){function e(a){return+(+a).toFixed(3)}return a._.cacher(function(a,f,h){a instanceof b&&(a=a.attr("d")),a=E(a);for(var j,k,l,m,n,o="",p={},q=0,r=0,s=a.length;s>r;r++){if(l=a[r],"M"==l[0])j=+l[1],k=+l[2];else{if(m=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6]),q+m>f){if(d&&!p.start){if(n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q),o+=["C"+e(n.start.x),e(n.start.y),e(n.m.x),e(n.m.y),e(n.x),e(n.y)],h)return o;p.start=o,o=["M"+e(n.x),e(n.y)+"C"+e(n.n.x),e(n.n.y),e(n.end.x),e(n.end.y),e(l[5]),e(l[6])].join(),q+=m,j=+l[5],k=+l[6];continue}if(!c&&!d)return n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q)}q+=m,j=+l[5],k=+l[6]}o+=l.shift()+l}return p.end=o,n=c?q:d?p:i(j,k,l[0],l[1],l[2],l[3],l[4],l[5],1)},null,a._.clone)}function i(a,b,c,d,e,f,g,h,i){var j=1-i,k=R(j,3),l=R(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*N.atan2(q-s,r-t)/O;return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}}function j(b,c,e,f,g,h,i,j){a.is(b,"array")||(b=[b,c,e,f,g,h,i,j]);var k=D.apply(null,b);return d(k.min.x,k.min.y,k.max.x-k.min.x,k.max.y-k.min.y)}function k(a,b,c){return b>=a.x&&b<=a.x+a.width&&c>=a.y&&c<=a.y+a.height}function l(a,b){return a=d(a),b=d(b),k(b,a.x,a.y)||k(b,a.x2,a.y)||k(b,a.x,a.y2)||k(b,a.x2,a.y2)||k(a,b.x,b.y)||k(a,b.x2,b.y)||k(a,b.x,b.y2)||k(a,b.x2,b.y2)||(a.x<b.x2&&a.x>b.x||b.x<a.x2&&b.x>a.x)&&(a.y<b.y2&&a.y>b.y||b.y<a.y2&&b.y>a.y)}function m(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function n(a,b,c,d,e,f,g,h,i){null==i&&(i=1),i=i>1?1:0>i?0:i;for(var j=i/2,k=12,l=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;k>p;p++){var q=j*l[p]+j,r=m(q,a,c,e,g),s=m(q,b,d,f,h),t=r*r+s*s;o+=n[p]*N.sqrt(t)}return j*o}function o(a,b,c,d,e,f,g,h,i){if(!(0>i||n(a,b,c,d,e,f,g,h)<i)){var j,k=1,l=k/2,m=k-l,o=.01;for(j=n(a,b,c,d,e,f,g,h,m);S(j-i)>o;)l/=2,m+=(i>j?1:-1)*l,j=n(a,b,c,d,e,f,g,h,m);return m}}function p(a,b,c,d,e,f,g,h){if(!(Q(a,c)<P(e,g)||P(a,c)>Q(e,g)||Q(b,d)<P(f,h)||P(b,d)>Q(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+Q(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+Q(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+Q(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+Q(f,h).toFixed(2)))return{x:l,y:m}}}}function q(a,b,c){var d=j(a),e=j(b);if(!l(d,e))return c?0:[];for(var f=n.apply(0,a),g=n.apply(0,b),h=~~(f/8),k=~~(g/8),m=[],o=[],q={},r=c?0:[],s=0;h+1>s;s++){var t=i.apply(0,a.concat(s/h));m.push({x:t.x,y:t.y,t:s/h})}for(s=0;k+1>s;s++)t=i.apply(0,b.concat(s/k)),o.push({x:t.x,y:t.y,t:s/k});for(s=0;h>s;s++)for(var u=0;k>u;u++){var v=m[s],w=m[s+1],x=o[u],y=o[u+1],z=S(w.x-v.x)<.001?"y":"x",A=S(y.x-x.x)<.001?"y":"x",B=p(v.x,v.y,w.x,w.y,x.x,x.y,y.x,y.y);if(B){if(q[B.x.toFixed(4)]==B.y.toFixed(4))continue;q[B.x.toFixed(4)]=B.y.toFixed(4);var C=v.t+S((B[z]-v[z])/(w[z]-v[z]))*(w.t-v.t),D=x.t+S((B[A]-x[A])/(y[A]-x[A]))*(y.t-x.t);C>=0&&1>=C&&D>=0&&1>=D&&(c?r++:r.push({x:B.x,y:B.y,t1:C,t2:D}))}}return r}function r(a,b){return t(a,b)}function s(a,b){return t(a,b,1)}function t(a,b,c){a=E(a),b=E(b);for(var d,e,f,g,h,i,j,k,l,m,n=c?0:[],o=0,p=a.length;p>o;o++){var r=a[o];if("M"==r[0])d=h=r[1],e=i=r[2];else{"C"==r[0]?(l=[d,e].concat(r.slice(1)),d=l[6],e=l[7]):(l=[d,e,d,e,h,i,h,i],d=h,e=i);for(var s=0,t=b.length;t>s;s++){var u=b[s];if("M"==u[0])f=j=u[1],g=k=u[2];else{"C"==u[0]?(m=[f,g].concat(u.slice(1)),f=m[6],g=m[7]):(m=[f,g,f,g,j,k,j,k],f=j,g=k);var v=q(l,m,c);if(c)n+=v;else{for(var w=0,x=v.length;x>w;w++)v[w].segment1=o,v[w].segment2=s,v[w].bez1=l,v[w].bez2=m;n=n.concat(v)}}}}}return n}function u(a,b,c){var d=v(a);return k(d,b,c)&&t(a,[["M",b,c],["H",d.x2+10]],1)%2==1}function v(a){var b=c(a);if(b.bbox)return J(b.bbox);if(!a)return d();a=E(a);for(var e,f=0,g=0,h=[],i=[],j=0,k=a.length;k>j;j++)if(e=a[j],"M"==e[0])f=e[1],g=e[2],h.push(f),i.push(g);else{var l=D(f,g,e[1],e[2],e[3],e[4],e[5],e[6]);h=h.concat(l.min.x,l.max.x),i=i.concat(l.min.y,l.max.y),f=e[5],g=e[6]}var m=P.apply(0,h),n=P.apply(0,i),o=Q.apply(0,h),p=Q.apply(0,i),q=d(m,n,o-m,p-n);return b.bbox=J(q),q}function w(a,b,c,d,f){if(f)return[["M",+a+ +f,b],["l",c-2*f,0],["a",f,f,0,0,1,f,f],["l",0,d-2*f],["a",f,f,0,0,1,-f,f],["l",2*f-c,0],["a",f,f,0,0,1,-f,-f],["l",0,2*f-d],["a",f,f,0,0,1,f,-f],["z"]];var g=[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]];return g.toString=e,g}function x(a,b,c,d,f){if(null==f&&null==d&&(d=c),a=+a,b=+b,c=+c,d=+d,null!=f)var g=Math.PI/180,h=a+c*Math.cos(-d*g),i=a+c*Math.cos(-f*g),j=b+c*Math.sin(-d*g),k=b+c*Math.sin(-f*g),l=[["M",h,j],["A",c,c,0,+(f-d>180),0,i,k]];else l=[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]];return l.toString=e,l}function y(b){var d=c(b),g=String.prototype.toLowerCase;if(d.rel)return f(d.rel);a.is(b,"array")&&a.is(b&&b[0],"array")||(b=a.parsePathString(b));var h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=b[0][1],j=b[0][2],k=i,l=j,m++,h.push(["M",i,j]));for(var n=m,o=b.length;o>n;n++){var p=h[n]=[],q=b[n];if(q[0]!=g.call(q[0]))switch(p[0]=g.call(q[0]),p[0]){case"a":p[1]=q[1],p[2]=q[2],p[3]=q[3],p[4]=q[4],p[5]=q[5],p[6]=+(q[6]-i).toFixed(3),p[7]=+(q[7]-j).toFixed(3);break;case"v":p[1]=+(q[1]-j).toFixed(3);break;case"m":k=q[1],l=q[2];default:for(var r=1,s=q.length;s>r;r++)p[r]=+(q[r]-(r%2?i:j)).toFixed(3)}else{p=h[n]=[],"m"==q[0]&&(k=q[1]+i,l=q[2]+j);for(var t=0,u=q.length;u>t;t++)h[n][t]=q[t]}var v=h[n].length;switch(h[n][0]){case"z":i=k,j=l;break;case"h":i+=+h[n][v-1];break;case"v":j+=+h[n][v-1];break;default:i+=+h[n][v-2],j+=+h[n][v-1]}}return h.toString=e,d.rel=f(h),h}function z(b){var d=c(b);if(d.abs)return f(d.abs);if(I(b,"array")&&I(b&&b[0],"array")||(b=a.parsePathString(b)),!b||!b.length)return[["M",0,0]];var g,h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=+b[0][1],j=+b[0][2],k=i,l=j,m++,h[0]=["M",i,j]);for(var n,o,p=3==b.length&&"M"==b[0][0]&&"R"==b[1][0].toUpperCase()&&"Z"==b[2][0].toUpperCase(),q=m,r=b.length;r>q;q++){if(h.push(n=[]),o=b[q],g=o[0],g!=g.toUpperCase())switch(n[0]=g.toUpperCase(),n[0]){case"A":n[1]=o[1],n[2]=o[2],n[3]=o[3],n[4]=o[4],n[5]=o[5],n[6]=+o[6]+i,n[7]=+o[7]+j;break;case"V":n[1]=+o[1]+j;break;case"H":n[1]=+o[1]+i;break;case"R":for(var s=[i,j].concat(o.slice(1)),t=2,u=s.length;u>t;t++)s[t]=+s[t]+i,s[++t]=+s[t]+j;h.pop(),h=h.concat(G(s,p));break;case"O":h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);break;case"U":h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));break;case"M":k=+o[1]+i,l=+o[2]+j;default:for(t=1,u=o.length;u>t;t++)n[t]=+o[t]+(t%2?i:j)}else if("R"==g)s=[i,j].concat(o.slice(1)),h.pop(),h=h.concat(G(s,p)),n=["R"].concat(o.slice(-2));else if("O"==g)h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);else if("U"==g)h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));else for(var v=0,w=o.length;w>v;v++)n[v]=o[v];if(g=g.toUpperCase(),"O"!=g)switch(n[0]){case"Z":i=+k,j=+l;break;case"H":i=n[1];break;case"V":j=n[1];break;case"M":k=n[n.length-2],l=n[n.length-1];default:i=n[n.length-2],j=n[n.length-1]}}return h.toString=e,d.abs=f(h),h}function A(a,b,c,d){return[a,b,c,d,c,d]}function B(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]}function C(b,c,d,e,f,g,h,i,j,k){var l,m=120*O/180,n=O/180*(+f||0),o=[],p=a._.cacher(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(b,c,-n),b=l.x,c=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(O/180*f),N.sin(O/180*f),(b-i)/2),r=(c-j)/2,s=q*q/(d*d)+r*r/(e*e);s>1&&(s=N.sqrt(s),d=s*d,e=s*e);var t=d*d,u=e*e,v=(g==h?-1:1)*N.sqrt(S((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*d*r/e+(b+i)/2,x=v*-e*q/d+(c+j)/2,y=N.asin(((c-x)/e).toFixed(9)),z=N.asin(((j-x)/e).toFixed(9));y=w>b?O-y:y,z=w>i?O-z:z,0>y&&(y=2*O+y),0>z&&(z=2*O+z),h&&y>z&&(y-=2*O),!h&&z>y&&(z-=2*O)}var A=z-y;if(S(A)>m){var B=z,D=i,E=j;z=y+m*(h&&z>y?1:-1),i=w+d*N.cos(z),j=x+e*N.sin(z),o=C(i,j,d,e,f,0,h,D,E,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),J=N.tan(A/4),K=4/3*d*J,L=4/3*e*J,M=[b,c],P=[b+K*G,c-L*F],Q=[i+K*I,j-L*H],R=[i,j];if(P[0]=2*M[0]-P[0],P[1]=2*M[1]-P[1],k)return[P,Q,R].concat(o);o=[P,Q,R].concat(o).join().split(",");for(var T=[],U=0,V=o.length;V>U;U++)T[U]=U%2?p(o[U-1],o[U],n).y:p(o[U],o[U+1],n).x;return T}function D(a,b,c,d,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=[],r=[[],[]],s=0;2>s;++s)if(0==s?(j=6*a-12*c+6*e,i=-3*a+9*c-9*e+3*g,k=3*c-3*a):(j=6*b-12*d+6*f,i=-3*b+9*d-9*f+3*h,k=3*d-3*b),S(i)<1e-12){if(S(j)<1e-12)continue;l=-k/j,l>0&&1>l&&q.push(l)}else o=j*j-4*k*i,p=N.sqrt(o),0>o||(m=(-j+p)/(2*i),m>0&&1>m&&q.push(m),n=(-j-p)/(2*i),n>0&&1>n&&q.push(n));for(var t,u=q.length,v=u;u--;)l=q[u],t=1-l,r[0][u]=t*t*t*a+3*t*t*l*c+3*t*l*l*e+l*l*l*g,r[1][u]=t*t*t*b+3*t*t*l*d+3*t*l*l*f+l*l*l*h;return r[0][v]=a,r[1][v]=b,r[0][v+1]=g,r[1][v+1]=h,r[0].length=r[1].length=v+2,{min:{x:P.apply(0,r[0]),y:P.apply(0,r[1])},max:{x:Q.apply(0,r[0]),y:Q.apply(0,r[1])}}}function E(a,b){var d=!b&&c(a);if(!b&&d.curve)return f(d.curve);for(var e=z(a),g=b&&z(b),h={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},i={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},j=(function(a,b,c){var d,e;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"].concat(C.apply(0,[b.x,b.y].concat(a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e].concat(a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"].concat(B(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"].concat(B(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"].concat(A(b.x,b.y,a[1],a[2]));break;case"H":a=["C"].concat(A(b.x,b.y,a[1],b.y));break;case"V":a=["C"].concat(A(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"].concat(A(b.x,b.y,b.X,b.Y))}return a}),k=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)m[b]="A",g&&(n[b]="A"),a.splice(b++,0,["C"].concat(c.splice(0,6)));a.splice(b,1),r=Q(e.length,g&&g.length||0)}},l=function(a,b,c,d,f){a&&b&&"M"==a[f][0]&&"M"!=b[f][0]&&(b.splice(f,0,["M",d.x,d.y]),c.bx=0,c.by=0,c.x=a[f][1],c.y=a[f][2],r=Q(e.length,g&&g.length||0))},m=[],n=[],o="",p="",q=0,r=Q(e.length,g&&g.length||0);r>q;q++){e[q]&&(o=e[q][0]),"C"!=o&&(m[q]=o,q&&(p=m[q-1])),e[q]=j(e[q],h,p),"A"!=m[q]&&"C"==o&&(m[q]="C"),k(e,q),g&&(g[q]&&(o=g[q][0]),"C"!=o&&(n[q]=o,q&&(p=n[q-1])),g[q]=j(g[q],i,p),"A"!=n[q]&&"C"==o&&(n[q]="C"),k(g,q)),l(e,g,h,i,q),l(g,e,i,h,q);var s=e[q],t=g&&g[q],u=s.length,v=g&&t.length;h.x=s[u-2],h.y=s[u-1],h.bx=M(s[u-4])||h.x,h.by=M(s[u-3])||h.y,i.bx=g&&(M(t[v-4])||i.x),i.by=g&&(M(t[v-3])||i.y),i.x=g&&t[v-2],i.y=g&&t[v-1]}return g||(d.curve=f(e)),g?[e,g]:e}function F(a,b){if(!b)return a;var c,d,e,f,g,h,i;for(a=E(a),e=0,g=a.length;g>e;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a}function G(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}var H=b.prototype,I=a.is,J=a._.clone,K="hasOwnProperty",L=/,?([a-z]),?/gi,M=parseFloat,N=Math,O=N.PI,P=N.min,Q=N.max,R=N.pow,S=N.abs,T=h(1),U=h(),V=h(0,1),W=a._unit2px,X={path:function(a){return a.attr("path")},circle:function(a){var b=W(a);return x(b.cx,b.cy,b.r)},ellipse:function(a){var b=W(a);return x(b.cx||0,b.cy||0,b.rx,b.ry)},rect:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height,b.rx,b.ry)},image:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height)},line:function(a){return"M"+[a.attr("x1")||0,a.attr("y1")||0,a.attr("x2"),a.attr("y2")]},polyline:function(a){return"M"+a.attr("points")},polygon:function(a){return"M"+a.attr("points")+"z"},deflt:function(a){var b=a.node.getBBox();return w(b.x,b.y,b.width,b.height)}};a.path=c,a.path.getTotalLength=T,a.path.getPointAtLength=U,a.path.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return V(a,b).end;var d=V(a,c,1);return b?V(d,b).end:d},H.getTotalLength=function(){return this.node.getTotalLength?this.node.getTotalLength():void 0},H.getPointAtLength=function(a){return U(this.attr("d"),a)},H.getSubpath=function(b,c){return a.path.getSubpath(this.attr("d"),b,c)},a._.box=d,a.path.findDotsAtSegment=i,a.path.bezierBBox=j,a.path.isPointInsideBBox=k,a.closest=function(b,c,e,f){for(var g=100,h=d(b-g/2,c-g/2,g,g),i=[],j=e[0].hasOwnProperty("x")?function(a){return{x:e[a].x,y:e[a].y}}:function(a){return{x:e[a],y:f[a]}},l=0;1e6>=g&&!l;){for(var m=0,n=e.length;n>m;m++){var o=j(m);if(k(h,o.x,o.y)){l++,i.push(o);break}}l||(g*=2,h=d(b-g/2,c-g/2,g,g))}if(1e6!=g){var p,q=1/0;for(m=0,n=i.length;n>m;m++){var r=a.len(b,c,i[m].x,i[m].y);q>r&&(q=r,i[m].len=r,p=i[m])}return p}},a.path.isBBoxIntersect=l,a.path.intersection=r,a.path.intersectionNumber=s,a.path.isPointInside=u,a.path.getBBox=v,a.path.get=X,a.path.toRelative=y,a.path.toAbsolute=z,a.path.toCubic=E,a.path.map=F,a.path.toString=e,a.path.clone=f}),d.plugin(function(a){var d=Math.max,e=Math.min,f=function(a){if(this.items=[],this.bindings={},this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)a[b]&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},g=f.prototype;g.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],a&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},g.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},g.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this},g.animate=function(d,e,f,g){"function"!=typeof f||f.length||(g=f,f=c.linear),d instanceof a._.Animation&&(g=d.callback,f=d.easing,e=f.dur,d=d.attr);var h=arguments;if(a.is(d,"array")&&a.is(h[h.length-1],"array"))var i=!0;var j,k=function(){j?this.b=j:j=this.b},l=0,m=this,n=g&&function(){++l==m.length&&g.call(this) +};return this.forEach(function(a,c){b.once("snap.animcreated."+a.id,k),i?h[c]&&a.animate.apply(a,h[c]):a.animate(d,e,f,n)})},g.remove=function(){for(;this.length;)this.pop().remove();return this},g.bind=function(a,b,c){var d={};if("function"==typeof b)this.bindings[a]=b;else{var e=c||a;this.bindings[a]=function(a){d[e]=a,b.attr(d)}}return this},g.attr=function(a){var b={};for(var c in a)this.bindings[c]?this.bindings[c](a[c]):b[c]=a[c];for(var d=0,e=this.items.length;e>d;d++)this.items[d].attr(b);return this},g.clear=function(){for(;this.length;)this.pop()},g.splice=function(a,b){a=0>a?d(this.length+a,0):a,b=d(0,e(this.length-a,b));var c,g=[],h=[],i=[];for(c=2;c<arguments.length;c++)i.push(arguments[c]);for(c=0;b>c;c++)h.push(this[a+c]);for(;c<this.length-a;c++)g.push(this[a+c]);var j=i.length;for(c=0;c<j+g.length;c++)this.items[a+c]=this[a+c]=j>c?i[c]:g[c-j];for(c=this.items.length=this.length-=b-j;this[c];)delete this[c++];return new f(h)},g.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0;return!1},g.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},g.getBBox=function(){for(var a=[],b=[],c=[],f=[],g=this.items.length;g--;)if(!this.items[g].removed){var h=this.items[g].getBBox();a.push(h.x),b.push(h.y),c.push(h.x+h.width),f.push(h.y+h.height)}return a=e.apply(0,a),b=e.apply(0,b),c=d.apply(0,c),f=d.apply(0,f),{x:a,y:b,x2:c,y2:f,width:c-a,height:f-b,cx:a+(c-a)/2,cy:b+(f-b)/2}},g.clone=function(a){a=new f;for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},g.toString=function(){return"Snap‘s set"},g.type="set",a.Set=f,a.set=function(){var a=new f;return arguments.length&&a.push.apply(a,Array.prototype.slice.call(arguments,0)),a}}),d.plugin(function(a,c){function d(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}}function e(b,c,e){c=p(c).replace(/\.{3}|\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];for(var f,g,h,i,l=Math.max(b.length,c.length),m=[],n=[],o=0;l>o;o++){if(h=b[o]||d(c[o]),i=c[o]||d(h),h[0]!=i[0]||"r"==h[0].toLowerCase()&&(h[2]!=i[2]||h[3]!=i[3])||"s"==h[0].toLowerCase()&&(h[3]!=i[3]||h[4]!=i[4])){b=a._.transform2matrix(b,e()),c=a._.transform2matrix(c,e()),m=[["m",b.a,b.b,b.c,b.d,b.e,b.f]],n=[["m",c.a,c.b,c.c,c.d,c.e,c.f]];break}for(m[o]=[],n[o]=[],f=0,g=Math.max(h.length,i.length);g>f;f++)f in h&&(m[o][f]=h[f]),f in i&&(n[o][f]=i[f])}return{from:k(m),to:k(n),f:j(m)}}function f(a){return a}function g(a){return function(b){return+b.toFixed(3)+a}}function h(a){return a.join(" ")}function i(b){return a.rgb(b[0],b[1],b[2])}function j(a){var b,c,d,e,f,g,h=0,i=[];for(b=0,c=a.length;c>b;b++){for(f="[",g=['"'+a[b][0]+'"'],d=1,e=a[b].length;e>d;d++)g[d]="val["+h++ +"]";f+=g+"]",i[b]=f}return Function("val","return Snap.path.toString.call(["+i+"])")}function k(a){for(var b=[],c=0,d=a.length;d>c;c++)for(var e=1,f=a[c].length;f>e;e++)b.push(a[c][e]);return b}function l(a){return isFinite(parseFloat(a))}function m(b,c){return a.is(b,"array")&&a.is(c,"array")?b.toString()==c.toString():!1}var n={},o=/[a-z]+$/i,p=String;n.stroke=n.fill="colour",c.prototype.equal=function(a,c){return b("snap.util.equal",this,a,c).firstDefined()},b.on("snap.util.equal",function(b,c){var d,q,r=p(this.attr(b)||""),s=this;if(l(r)&&l(c))return{from:parseFloat(r),to:parseFloat(c),f:f};if("colour"==n[b])return d=a.color(r),q=a.color(c),{from:[d.r,d.g,d.b,d.opacity],to:[q.r,q.g,q.b,q.opacity],f:i};if("viewBox"==b)return d=this.attr(b).vb.split(" ").map(Number),q=c.split(" ").map(Number),{from:d,to:q,f:h};if("transform"==b||"gradientTransform"==b||"patternTransform"==b)return c instanceof a.Matrix&&(c=c.toTransformString()),a._.rgTransform.test(c)||(c=a._.svgTransform2string(c)),e(r,c,function(){return s.getBBox(1)});if("d"==b||"path"==b)return d=a.path.toCubic(r,c),{from:k(d[0]),to:k(d[1]),f:j(d[0])};if("points"==b)return d=p(r).split(a._.separator),q=p(c).split(a._.separator),{from:d,to:q,f:function(a){return a}};var t=r.match(o),u=p(c).match(o);return t&&m(t,u)?{from:parseFloat(r),to:parseFloat(c),f:g(t)}:{from:this.asPX(b),to:this.asPX(b,c),f:f}})}),d.plugin(function(a,c,d,e){for(var f=c.prototype,g="hasOwnProperty",h=("createTouch"in e.doc),i=["click","dblclick","mousedown","mousemove","mouseout","mouseover","mouseup","touchstart","touchmove","touchend","touchcancel"],j={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},k=(function(a,b){var c="y"==a?"scrollTop":"scrollLeft",d=b&&b.node?b.node.ownerDocument:e.doc;return d[c in d.documentElement?"documentElement":"body"][c]}),l=function(){return this.originalEvent.preventDefault()},m=function(){return this.originalEvent.stopPropagation()},n=function(a,b,c,d){var e=h&&j[b]?j[b]:b,f=function(e){var f=k("y",d),i=k("x",d);if(h&&j[g](b))for(var n=0,o=e.targetTouches&&e.targetTouches.length;o>n;n++)if(e.targetTouches[n].target==a||a.contains(e.targetTouches[n].target)){var p=e;e=e.targetTouches[n],e.originalEvent=p,e.preventDefault=l,e.stopPropagation=m;break}var q=e.clientX+i,r=e.clientY+f;return c.call(d,e,q,r)};return b!==e&&a.addEventListener(b,f,!1),a.addEventListener(e,f,!1),function(){return b!==e&&a.removeEventListener(b,f,!1),a.removeEventListener(e,f,!1),!0}},o=[],p=function(a){for(var c,d=a.clientX,e=a.clientY,f=k("y"),g=k("x"),i=o.length;i--;){if(c=o[i],h){for(var j,l=a.touches&&a.touches.length;l--;)if(j=a.touches[l],j.identifier==c.el._drag.id||c.el.node.contains(j.target)){d=j.clientX,e=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();{var m=c.el.node;m.nextSibling,m.parentNode,m.style.display}d+=g,e+=f,b("snap.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},q=function(c){a.unmousemove(p).unmouseup(q);for(var d,e=o.length;e--;)d=o[e],d.el._drag={},b("snap.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,c),b.off("snap.drag.*."+d.el.id);o=[]},r=i.length;r--;)!function(b){a[b]=f[b]=function(c,d){if(a.is(c,"function"))this.events=this.events||[],this.events.push({name:b,f:c,unbind:n(this.node||document,b,c,d||this)});else for(var e=0,f=this.events.length;f>e;e++)if(this.events[e].name==b)try{this.events[e].f.call(this)}catch(g){}return this},a["un"+b]=f["un"+b]=function(a){for(var c=this.events||[],d=c.length;d--;)if(c[d].name==b&&(c[d].f==a||!a))return c[d].unbind(),c.splice(d,1),!c.length&&delete this.events,this;return this}}(i[r]);f.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},f.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var s=[];f.drag=function(c,d,e,f,g,h){function i(i,j,l){(i.originalEvent||i).preventDefault(),k._drag.x=j,k._drag.y=l,k._drag.id=i.identifier,!o.length&&a.mousemove(p).mouseup(q),o.push({el:k,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("snap.drag.start."+k.id,d),c&&b.on("snap.drag.move."+k.id,c),e&&b.on("snap.drag.end."+k.id,e),b("snap.drag.start."+k.id,g||f||k,j,l,i)}function j(a,c,d){b("snap.draginit."+k.id,k,a,c,d)}var k=this;if(!arguments.length){var l;return k.drag(function(a,b){this.attr({transform:l+(l?"T":"t")+[a,b]})},function(){l=this.transform().local})}return b.on("snap.draginit."+k.id,i),k._drag={},s.push({el:k,start:i,init:j}),k.mousedown(j),k},f.undrag=function(){for(var c=s.length;c--;)s[c].el==this&&(this.unmousedown(s[c].init),s.splice(c,1),b.unbind("snap.drag.*."+this.id),b.unbind("snap.draginit."+this.id));return!s.length&&a.unmousemove(p).unmouseup(q),this}}),d.plugin(function(a,c,d){var e=(c.prototype,d.prototype),f=/^\s*url\((.+)\)/,g=String,h=a._.$;a.filter={},e.filter=function(b){var d=this;"svg"!=d.type&&(d=d.paper);var e=a.parse(g(b)),f=a._.id(),i=(d.node.offsetWidth,d.node.offsetHeight,h("filter"));return h(i,{id:f,filterUnits:"userSpaceOnUse"}),i.appendChild(e.node),d.defs.appendChild(i),new c(i)},b.on("snap.util.getattr.filter",function(){b.stop();var c=h(this.node,"filter");if(c){var d=g(c).match(f);return d&&a.select(d[1])}}),b.on("snap.util.attr.filter",function(d){if(d instanceof c&&"filter"==d.type){b.stop();var e=d.node.id;e||(h(d.node,{id:d.id}),e=d.id),h(this.node,{filter:a.url(e)})}d&&"none"!=d||(b.stop(),this.node.removeAttribute("filter"))}),a.filter.blur=function(b,c){null==b&&(b=2);var d=null==c?b:[b,c];return a.format('<feGaussianBlur stdDeviation="{def}"/>',{def:d})},a.filter.blur.toString=function(){return this()},a.filter.shadow=function(b,c,d,e,f){return"string"==typeof d&&(e=d,f=e,d=4),"string"!=typeof e&&(f=e,e="#000"),e=e||"#000",null==d&&(d=4),null==f&&(f=1),null==b&&(b=0,c=2),null==c&&(c=b),e=a.color(e),a.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>',{color:e,dx:b,dy:c,blur:d,opacity:f})},a.filter.shadow.toString=function(){return this()},a.filter.grayscale=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>',{a:.2126+.7874*(1-b),b:.7152-.7152*(1-b),c:.0722-.0722*(1-b),d:.2126-.2126*(1-b),e:.7152+.2848*(1-b),f:.0722-.0722*(1-b),g:.2126-.2126*(1-b),h:.0722+.9278*(1-b)})},a.filter.grayscale.toString=function(){return this()},a.filter.sepia=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>',{a:.393+.607*(1-b),b:.769-.769*(1-b),c:.189-.189*(1-b),d:.349-.349*(1-b),e:.686+.314*(1-b),f:.168-.168*(1-b),g:.272-.272*(1-b),h:.534-.534*(1-b),i:.131+.869*(1-b)})},a.filter.sepia.toString=function(){return this()},a.filter.saturate=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="saturate" values="{amount}"/>',{amount:1-b})},a.filter.saturate.toString=function(){return this()},a.filter.hueRotate=function(b){return b=b||0,a.format('<feColorMatrix type="hueRotate" values="{angle}"/>',{angle:b})},a.filter.hueRotate.toString=function(){return this()},a.filter.invert=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>',{amount:b,amount2:1-b})},a.filter.invert.toString=function(){return this()},a.filter.brightness=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>',{amount:b})},a.filter.brightness.toString=function(){return this()},a.filter.contrast=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>',{amount:b,amount2:.5-b/2})},a.filter.contrast.toString=function(){return this()}}),d.plugin(function(a,b){var c=a._.box,d=a.is,e=/^[^a-z]*([tbmlrc])/i,f=function(){return"T"+this.dx+","+this.dy};b.prototype.getAlign=function(a,b){null==b&&d(a,"string")&&(b=a,a=null),a=a||this.paper;var g=a.getBBox?a.getBBox():c(a),h=this.getBBox(),i={};switch(b=b&&b.match(e),b=b?b[1].toLowerCase():"c"){case"t":i.dx=0,i.dy=g.y-h.y;break;case"b":i.dx=0,i.dy=g.y2-h.y2;break;case"m":i.dx=0,i.dy=g.cy-h.cy;break;case"l":i.dx=g.x-h.x,i.dy=0;break;case"r":i.dx=g.x2-h.x2,i.dy=0;break;default:i.dx=g.cx-h.cx,i.dy=0}return i.toString=f,i},b.prototype.align=function(a,b){return this.transform("..."+this.getAlign(a,b))}}),d}); diff --git a/web/pgadmin/misc/static/explain/js/snap.svg.js b/web/pgadmin/misc/static/explain/js/snap.svg.js new file mode 100644 index 0000000..ef0fb6d --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg.js @@ -0,0 +1,8149 @@ +// Snap.svg 0.4.1 +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// build: 2015-04-13 +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ┌────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.4.2 - JavaScript Events Library │ \\ +// ├────────────────────────────────────────────────────────────┤ \\ +// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// └────────────────────────────────────────────────────────────┘ \\ +(function (glob) { + var version = "0.4.2", + has = "hasOwnProperty", + separator = /[\.\/]/, + comaseparator = /\s*,\s*/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + firstDefined = function () { + for (var i = 0, ii = this.length; i < ii; i++) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + lastDefined = function () { + var i = this.length; + while (--i) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + /*\ + * eve + [ method ] + * Fires event with given `name`, given scope and other parameters. + > Arguments + - name (string) name of the *event*, dot (`.`) or slash (`/`) separated + - scope (object) context for the event handlers + - varargs (...) the rest of arguments will be sent to event handlers + = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value. + \*/ + eve = function (name, scope) { + name = String(name); + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + ce = current_event, + errors = []; + out.firstDefined = firstDefined; + out.lastDefined = lastDefined; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + break; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + } + } + stop = oldstop; + current_event = ce; + return out; + }; + // Undocumented. Debug only. + eve._events = events; + /*\ + * eve.listeners + [ method ] + * Internal method which gives you array of all event handlers that will be triggered by the given `name`. + > Arguments + - name (string) name of the event, dot (`.`) or slash (`/`) separated + = (array) array of event handlers + \*/ + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + /*\ + * eve.on + [ method ] + ** + * Binds given event handler with a given name. You can use wildcards “`*`” for the names: + | eve.on("*.under.*", f); + | eve("mouse.under.floor"); // triggers f + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. + > Example: + | eve.on("mouse", eatIt)(2); + | eve.on("mouse", scream); + | eve.on("mouse", catchIt)(1); + * This will ensure that `catchIt` function will be called before `eatIt`. + * + * If you want to put your handler before non-indexed handlers, specify a negative value. + * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. + \*/ + eve.on = function (name, f) { + name = String(name); + if (typeof f != "function") { + return function () {}; + } + var names = name.split(comaseparator); + for (var i = 0, ii = names.length; i < ii; i++) { + (function (name) { + var names = name.split(separator), + e = events, + exist; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + exist = true; + break; + } + !exist && e.f.push(f); + }(names[i])); + } + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + /*\ + * eve.f + [ method ] + ** + * Returns function that will fire given event with optional arguments. + * Arguments that will be passed to the result function will be also + * concated to the list of final arguments. + | el.onclick = eve.f("click", 1, 2); + | eve.on("click", function (a, b, c) { + | console.log(a, b, c); // 1, 2, [event object] + | }); + > Arguments + - event (string) event name + - varargs (…) and any other arguments + = (function) possible event handler function + \*/ + eve.f = function (event) { + var attrs = [].slice.call(arguments, 1); + return function () { + eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); + }; + }; + /*\ + * eve.stop + [ method ] + ** + * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. + \*/ + eve.stop = function () { + stop = 1; + }; + /*\ + * eve.nt + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + > Arguments + ** + - subname (string) #optional subname of the event + ** + = (string) name of the event, if `subname` is not specified + * or + = (boolean) `true`, if current event’s name contains `subname` + \*/ + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + /*\ + * eve.nts + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + ** + = (array) names of the event + \*/ + eve.nts = function () { + return current_event.split(separator); + }; + /*\ + * eve.off + [ method ] + ** + * Removes given function from the list of event listeners assigned to given name. + * If no arguments specified all the events will be cleared. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + \*/ + /*\ + * eve.unbind + [ method ] + ** + * See @eve.off + \*/ + eve.off = eve.unbind = function (name, f) { + if (!name) { + eve._events = events = {n: {}}; + return; + } + var names = name.split(comaseparator); + if (names.length > 1) { + for (var i = 0, ii = names.length; i < ii; i++) { + eve.off(names[i], f); + } + return; + } + names = name.split(separator); + var e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + /*\ + * eve.once + [ method ] + ** + * Binds given event handler with a given name to only run once then unbind itself. + | eve.once("login", f); + | eve("login"); // triggers f + | eve("login"); // no listeners + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) same return function as @eve.on + \*/ + eve.once = function (name, f) { + var f2 = function () { + eve.unbind(name, f2); + return f.apply(this, arguments); + }; + return eve.on(name, f2); + }; + /*\ + * eve.version + [ property (string) ] + ** + * Current version of the library. + \*/ + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define === "function" && define.amd ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); +})(this); + +(function (glob, factory) { + // AMD support + if (typeof define == "function" && define.amd) { + // Define as an anonymous module + define(["eve"], function (eve) { + return factory(glob, eve); + }); + } else if (typeof exports != 'undefined') { + // Next for Node.js or CommonJS + var eve = require('eve'); + module.exports = factory(glob, eve); + } else { + // Browser globals (glob is window) + // Snap adds itself to window + factory(glob, glob.eve); + } +}(window || this, function (window, eve) { +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +var mina = (function (eve) { + var animations = {}, + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + isArray = Array.isArray || function (a) { + return a instanceof Array || + Object.prototype.toString.call(a) == "[object Array]"; + }, + idgen = 0, + idprefix = "M" + (+new Date).toString(36), + ID = function () { + return idprefix + (idgen++).toString(36); + }, + diff = function (a, b, A, B) { + if (isArray(a)) { + res = []; + for (var i = 0, ii = a.length; i < ii; i++) { + res[i] = diff(a[i], b, A[i], B); + } + return res; + } + var dif = (A - a) / (B - b); + return function (bb) { + return a + dif * (bb - b); + }; + }, + timer = Date.now || function () { + return +new Date; + }, + sta = function (val) { + var a = this; + if (val == null) { + return a.s; + } + var ds = a.s - val; + a.b += a.dur * ds; + a.B += a.dur * ds; + a.s = val; + }, + speed = function (val) { + var a = this; + if (val == null) { + return a.spd; + } + a.spd = val; + }, + duration = function (val) { + var a = this; + if (val == null) { + return a.dur; + } + a.s = a.s * val / a.dur; + a.dur = val; + }, + stopit = function () { + var a = this; + delete animations[a.id]; + a.update(); + eve("mina.stop." + a.id, a); + }, + pause = function () { + var a = this; + if (a.pdif) { + return; + } + delete animations[a.id]; + a.update(); + a.pdif = a.get() - a.b; + }, + resume = function () { + var a = this; + if (!a.pdif) { + return; + } + a.b = a.get() - a.pdif; + delete a.pdif; + animations[a.id] = a; + }, + update = function () { + var a = this, + res; + if (isArray(a.start)) { + res = []; + for (var j = 0, jj = a.start.length; j < jj; j++) { + res[j] = +a.start[j] + + (a.end[j] - a.start[j]) * a.easing(a.s); + } + } else { + res = +a.start + (a.end - a.start) * a.easing(a.s); + } + a.set(res); + }, + frame = function () { + var len = 0; + for (var i in animations) if (animations.hasOwnProperty(i)) { + var a = animations[i], + b = a.get(), + res; + len++; + a.s = (b - a.b) / (a.dur / a.spd); + if (a.s >= 1) { + delete animations[i]; + a.s = 1; + len--; + (function (a) { + setTimeout(function () { + eve("mina.finish." + a.id, a); + }); + }(a)); + } + a.update(); + } + len && requestAnimFrame(frame); + }, + /*\ + * mina + [ method ] + ** + * Generic animation of numbers + ** + - a (number) start _slave_ number + - A (number) end _slave_ number + - b (number) start _master_ number (start time in general case) + - B (number) end _master_ number (end time in gereal case) + - get (function) getter of _master_ number (see @mina.time) + - set (function) setter of _slave_ number + - easing (function) #optional easing function, default is @mina.linear + = (object) animation descriptor + o { + o id (string) animation id, + o start (number) start _slave_ number, + o end (number) end _slave_ number, + o b (number) start _master_ number, + o s (number) animation status (0..1), + o dur (number) animation duration, + o spd (number) animation speed, + o get (function) getter of _master_ number (see @mina.time), + o set (function) setter of _slave_ number, + o easing (function) easing function, default is @mina.linear, + o status (function) status getter/setter, + o speed (function) speed getter/setter, + o duration (function) duration getter/setter, + o stop (function) animation stopper + o pause (function) pauses the animation + o resume (function) resumes the animation + o update (function) calles setter with the right value of the animation + o } + \*/ + mina = function (a, A, b, B, get, set, easing) { + var anim = { + id: ID(), + start: a, + end: A, + b: b, + s: 0, + dur: B - b, + spd: 1, + get: get, + set: set, + easing: easing || mina.linear, + status: sta, + speed: speed, + duration: duration, + stop: stopit, + pause: pause, + resume: resume, + update: update + }; + animations[anim.id] = anim; + var len = 0, i; + for (i in animations) if (animations.hasOwnProperty(i)) { + len++; + if (len == 2) { + break; + } + } + len == 1 && requestAnimFrame(frame); + return anim; + }; + /*\ + * mina.time + [ method ] + ** + * Returns the current time. Equivalent to: + | function () { + | return (new Date).getTime(); + | } + \*/ + mina.time = timer; + /*\ + * mina.getById + [ method ] + ** + * Returns an animation by its id + - id (string) animation's id + = (object) See @mina + \*/ + mina.getById = function (id) { + return animations[id] || null; + }; + + /*\ + * mina.linear + [ method ] + ** + * Default linear easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.linear = function (n) { + return n; + }; + /*\ + * mina.easeout + [ method ] + ** + * Easeout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeout = function (n) { + return Math.pow(n, 1.7); + }; + /*\ + * mina.easein + [ method ] + ** + * Easein easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easein = function (n) { + return Math.pow(n, .48); + }; + /*\ + * mina.easeinout + [ method ] + ** + * Easeinout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeinout = function (n) { + if (n == 1) { + return 1; + } + if (n == 0) { + return 0; + } + var q = .48 - n / 1.04, + Q = Math.sqrt(.1734 + q * q), + x = Q - q, + X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }; + /*\ + * mina.backin + [ method ] + ** + * Backin easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backin = function (n) { + if (n == 1) { + return 1; + } + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }; + /*\ + * mina.backout + [ method ] + ** + * Backout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backout = function (n) { + if (n == 0) { + return 0; + } + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }; + /*\ + * mina.elastic + [ method ] + ** + * Elastic easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.elastic = function (n) { + if (n == !!n) { + return n; + } + return Math.pow(2, -10 * n) * Math.sin((n - .075) * + (2 * Math.PI) / .3) + 1; + }; + /*\ + * mina.bounce + [ method ] + ** + * Bounce easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.bounce = function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + }; + window.mina = mina; + return mina; +})(typeof eve == "undefined" ? function () {} : eve); +// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var Snap = (function(root) { +Snap.version = "0.4.0"; +/*\ + * Snap + [ method ] + ** + * Creates a drawing surface or wraps existing SVG element. + ** + - width (number|string) width of surface + - height (number|string) height of surface + * or + - DOM (SVGElement) element to be wrapped into Snap structure + * or + - array (array) array of elements (will return set of elements) + * or + - query (string) CSS query selector + = (object) @Element +\*/ +function Snap(w, h) { + if (w) { + if (w.nodeType) { + return wrap(w); + } + if (is(w, "array") && Snap.set) { + return Snap.set.apply(Snap, w); + } + if (w instanceof Element) { + return w; + } + if (h == null) { + w = glob.doc.querySelector(String(w)); + return wrap(w); + } + } + w = w == null ? "100%" : w; + h = h == null ? "100%" : h; + return new Paper(w, h); +} +Snap.toString = function () { + return "Snap v" + this.version; +}; +Snap._ = {}; +var glob = { + win: root.window, + doc: root.window.document +}; +Snap._.glob = glob; +var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + round = math.round, + E = "", + S = " ", + objectToString = Object.prototype.toString, + ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + reURLValue = /^url\(#?([^)]+)\)$/, + separator = Snap._.separator = /[,\s]+/, + whitespace = /[\s]/g, + commaSpaces = /[\s]*,[\s]*/, + hsrg = {hs: 1, rg: 1}, + pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig, + idgen = 0, + idprefix = "S" + (+new Date).toString(36), + ID = function (el) { + return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36); + }, + xlink = "http://www.w3.org/1999/xlink", + xmlns = "http://www.w3.org/2000/svg", + hub = {}, + URL = Snap.url = function (url) { + return "url('#" + url + "')"; + }; + +function $(el, attr) { + if (attr) { + if (el == "#text") { + el = glob.doc.createTextNode(attr.text || attr["#text"] || ""); + } + if (el == "#comment") { + el = glob.doc.createComment(attr.text || attr["#text"] || ""); + } + if (typeof el == "string") { + el = $(el); + } + if (typeof attr == "string") { + if (el.nodeType == 1) { + if (attr.substring(0, 6) == "xlink:") { + return el.getAttributeNS(xlink, attr.substring(6)); + } + if (attr.substring(0, 4) == "xml:") { + return el.getAttributeNS(xmlns, attr.substring(4)); + } + return el.getAttribute(attr); + } else if (attr == "text") { + return el.nodeValue; + } else { + return null; + } + } + if (el.nodeType == 1) { + for (var key in attr) if (attr[has](key)) { + var val = Str(attr[key]); + if (val) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), val); + } else if (key.substring(0, 4) == "xml:") { + el.setAttributeNS(xmlns, key.substring(4), val); + } else { + el.setAttribute(key, val); + } + } else { + el.removeAttribute(key); + } + } + } else if ("text" in attr) { + el.nodeValue = attr.text; + } + } else { + el = glob.doc.createElementNS(xmlns, el); + } + return el; +} +Snap._.$ = $; +Snap._.id = ID; +function getAttrs(el) { + var attrs = el.attributes, + name, + out = {}; + for (var i = 0; i < attrs.length; i++) { + if (attrs[i].namespaceURI == xlink) { + name = "xlink:"; + } else { + name = ""; + } + name += attrs[i].name; + out[name] = attrs[i].textContent; + } + return out; +} +function is(o, type) { + type = Str.prototype.toLowerCase.call(type); + if (type == "finite") { + return isFinite(o); + } + if (type == "array" && + (o instanceof Array || Array.isArray && Array.isArray(o))) { + return true; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; +} +/*\ + * Snap.format + [ method ] + ** + * Replaces construction of type `{<name>}` to the corresponding argument + ** + - token (string) string to format + - json (object) object which properties are used as a replacement + = (string) formatted string + > Usage + | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z" + | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { + | x: 10, + | y: 20, + | dim: { + | width: 40, + | height: 50, + | "negative width": -40 + | } + | })); +\*/ +Snap.format = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return Str(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; +})(); +function clone(obj) { + if (typeof obj == "function" || Object(obj) !== obj) { + return obj; + } + var res = new obj.constructor; + for (var key in obj) if (obj[has](key)) { + res[key] = clone(obj[key]); + } + return res; +} +Snap._.clone = clone; +function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } +} +function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f.apply(scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; +} +Snap._.cacher = cacher; +function angle(x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3); + } +} +function rad(deg) { + return deg % 360 * PI / 180; +} +function deg(rad) { + return rad * 180 / PI % 360; +} +function x_y() { + return this.x + S + this.y; +} +function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; +} + +/*\ + * Snap.rad + [ method ] + ** + * Transform angle to radians + - deg (number) angle in degrees + = (number) angle in radians +\*/ +Snap.rad = rad; +/*\ + * Snap.deg + [ method ] + ** + * Transform angle to degrees + - rad (number) angle in radians + = (number) angle in degrees +\*/ +Snap.deg = deg; +/*\ + * Snap.sin + [ method ] + ** + * Equivalent to `Math.sin()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) sin +\*/ +Snap.sin = function (angle) { + return math.sin(Snap.rad(angle)); +}; +/*\ + * Snap.tan + [ method ] + ** + * Equivalent to `Math.tan()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) tan +\*/ +Snap.tan = function (angle) { + return math.tan(Snap.rad(angle)); +}; +/*\ + * Snap.cos + [ method ] + ** + * Equivalent to `Math.cos()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) cos +\*/ +Snap.cos = function (angle) { + return math.cos(Snap.rad(angle)); +}; +/*\ + * Snap.asin + [ method ] + ** + * Equivalent to `Math.asin()` only works with degrees, not radians. + - num (number) value + = (number) asin in degrees +\*/ +Snap.asin = function (num) { + return Snap.deg(math.asin(num)); +}; +/*\ + * Snap.acos + [ method ] + ** + * Equivalent to `Math.acos()` only works with degrees, not radians. + - num (number) value + = (number) acos in degrees +\*/ +Snap.acos = function (num) { + return Snap.deg(math.acos(num)); +}; +/*\ + * Snap.atan + [ method ] + ** + * Equivalent to `Math.atan()` only works with degrees, not radians. + - num (number) value + = (number) atan in degrees +\*/ +Snap.atan = function (num) { + return Snap.deg(math.atan(num)); +}; +/*\ + * Snap.atan2 + [ method ] + ** + * Equivalent to `Math.atan2()` only works with degrees, not radians. + - num (number) value + = (number) atan2 in degrees +\*/ +Snap.atan2 = function (num) { + return Snap.deg(math.atan2(num)); +}; +/*\ + * Snap.angle + [ method ] + ** + * Returns an angle between two or three points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + - x3 (number) #optional x coord of third point + - y3 (number) #optional y coord of third point + = (number) angle in degrees +\*/ +Snap.angle = angle; +/*\ + * Snap.len + [ method ] + ** + * Returns distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len = function (x1, y1, x2, y2) { + return Math.sqrt(Snap.len2(x1, y1, x2, y2)); +}; +/*\ + * Snap.len2 + [ method ] + ** + * Returns squared distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len2 = function (x1, y1, x2, y2) { + return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); +}; +/*\ + * Snap.closestPoint + [ method ] + ** + * Returns closest point to a given one on a given path. + > Parameters + - path (Element) path element + - x (number) x coord of a point + - y (number) y coord of a point + = (object) in format + { + x (number) x coord of the point on the path + y (number) y coord of the point on the path + length (number) length of the path to the point + distance (number) distance from the given point to the path + } +\*/ +// Copied from http://bl.ocks.org/mbostock/8027637 +Snap.closestPoint = function (path, x, y) { + function distance2(p) { + var dx = p.x - x, + dy = p.y - y; + return dx * dx + dy * dy; + } + var pathNode = path.node, + pathLength = pathNode.getTotalLength(), + precision = pathLength / pathNode.pathSegList.numberOfItems * .125, + best, + bestLength, + bestDistance = Infinity; + + // linear scan for coarse approximation + for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { + if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) { + best = scan, bestLength = scanLength, bestDistance = scanDistance; + } + } + + // binary search for precise estimate + precision *= .5; + while (precision > .5) { + var before, + after, + beforeLength, + afterLength, + beforeDistance, + afterDistance; + if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) { + best = before, bestLength = beforeLength, bestDistance = beforeDistance; + } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) { + best = after, bestLength = afterLength, bestDistance = afterDistance; + } else { + precision *= .5; + } + } + + best = { + x: best.x, + y: best.y, + length: bestLength, + distance: Math.sqrt(bestDistance) + }; + return best; +} +/*\ + * Snap.is + [ method ] + ** + * Handy replacement for the `typeof` operator + - o (…) any object or primitive + - type (string) name of the type, e.g., `string`, `function`, `number`, etc. + = (boolean) `true` if given value is of given type +\*/ +Snap.is = is; +/*\ + * Snap.snapTo + [ method ] + ** + * Snaps given value to given grid + - values (array|number) given array of values or step of the grid + - value (number) value to adjust + - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`. + = (number) adjusted value +\*/ +Snap.snapTo = function (values, value, tolerance) { + tolerance = is(tolerance, "finite") ? tolerance : 10; + if (is(values, "array")) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; +}; +// Colour +/*\ + * Snap.getRGB + [ method ] + ** + * Parses color string as RGB object + - color (string) color string in one of the following formats: + # <ul> + # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li> + # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li> + # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li> + # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li> + # <li>rgba(•••, •••, •••, •••) — also with opacity</li> + # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li> + # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li> + # <li>hsba(•••, •••, •••, •••) — also with opacity</li> + # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li> + # <li>hsla(•••, •••, •••, •••) — also with opacity</li> + # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li> + # </ul> + * Note that `%` can be used any time: `rgb(20%, 255, 50%)`. + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) true if string can't be parsed + o } +\*/ +Snap.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + if (!colour) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsl2rgb(red, green, blue, opacity); + } + red = mmin(math.round(red), 255); + green = mmin(math.round(green), 255); + blue = mmin(math.round(blue), 255); + opacity = mmin(mmax(opacity, 0), 1); + rgb = {r: red, g: green, b: blue, toString: rgbtoString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + rgb.opacity = is(opacity, "finite") ? opacity : 1; + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; +}, Snap); +/*\ + * Snap.hsb + [ method ] + ** + * Converts HSB values to a hex representation of the color + - h (number) hue + - s (number) saturation + - b (number) value or brightness + = (string) hex representation of the color +\*/ +Snap.hsb = cacher(function (h, s, b) { + return Snap.hsb2rgb(h, s, b).hex; +}); +/*\ + * Snap.hsl + [ method ] + ** + * Converts HSL values to a hex representation of the color + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (string) hex representation of the color +\*/ +Snap.hsl = cacher(function (h, s, l) { + return Snap.hsl2rgb(h, s, l).hex; +}); +/*\ + * Snap.rgb + [ method ] + ** + * Converts RGB values to a hex representation of the color + - r (number) red + - g (number) green + - b (number) blue + = (string) hex representation of the color +\*/ +Snap.rgb = cacher(function (r, g, b, o) { + if (is(o, "finite")) { + var round = math.round; + return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")"; + } + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); +}); +var toHex = function (color) { + var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0], + red = "rgb(255, 0, 0)"; + toHex = cacher(function (color) { + if (color.toLowerCase() == "red") { + return red; + } + i.style.color = red; + i.style.color = color; + var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + return out == red ? null : out; + }); + return toHex(color); +}, +hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; +}, +hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; +}, +rgbtoString = function () { + return this.opacity == 1 || this.opacity == null ? + this.hex : + "rgba(" + [this.r, this.g, this.b, this.opacity] + ")"; +}, +prepareRGB = function (r, g, b) { + if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && is(r, string)) { + var clr = Snap.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; +}, +packageRGB = function (r, g, b, o) { + r = math.round(r * 255); + g = math.round(g * 255); + b = math.round(b * 255); + var rgb = { + r: r, + g: g, + b: b, + opacity: is(o, "finite") ? o : 1, + hex: Snap.rgb(r, g, b), + toString: rgbtoString + }; + is(o, "finite") && (rgb.opacity = o); + return rgb; +}; +/*\ + * Snap.color + [ method ] + ** + * Parses the color string and returns an object featuring the color's component values + - clr (string) color string in one of the supported formats (see @Snap.getRGB) + = (object) Combined RGB/HSB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) `true` if string can't be parsed, + o h (number) hue, + o s (number) saturation, + o v (number) value (brightness), + o l (number) lightness + o } +\*/ +Snap.color = function (clr) { + var rgb; + if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = Snap.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = Snap.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else { + if (is(clr, "string")) { + clr = Snap.getRGB(clr); + } + if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) { + rgb = Snap.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = Snap.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + clr.error = 1; + } + } + clr.toString = rgbtoString; + return clr; +}; +/*\ + * Snap.hsb2rgb + [ method ] + ** + * Converts HSB values to an RGB object + - h (number) hue + - s (number) saturation + - v (number) value or brightness + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsb2rgb = function (h, s, v, o) { + if (is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + o = h.o; + h = h.h; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.hsl2rgb + [ method ] + ** + * Converts HSL values to an RGB object + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsl2rgb = function (h, s, l, o) { + if (is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.rgb2hsb + [ method ] + ** + * Converts RGB values to an HSB object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSB object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o b (number) brightness + o } +\*/ +Snap.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; +}; +/*\ + * Snap.rgb2hsl + [ method ] + ** + * Converts RGB values to an HSL object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSL object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o l (number) luminosity + o } +\*/ +Snap.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; +}; + +// Transformations +/*\ + * Snap.parsePathString + [ method ] + ** + * Utility method + ** + * Parses given path string into an array of arrays of path segments + - pathString (string|array) path string or array of segments (in the last case it is returned straight away) + = (array) array of segments +\*/ +Snap.parsePathString = function (pathString) { + if (!pathString) { + return null; + } + var pth = Snap.path(pathString); + if (pth.arr) { + return Snap.path.clone(pth.arr); + } + + var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0}, + data = []; + if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption + data = Snap.path.clone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b].concat(params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "o" && params.length == 1) { + data.push([b, params[0]]); + } + if (name == "r") { + data.push([b].concat(params)); + } else while (params.length >= paramCounts[name]) { + data.push([b].concat(params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = Snap.path.toString; + pth.arr = Snap.path.clone(data); + return data; +}; +/*\ + * Snap.parseTransformString + [ method ] + ** + * Utility method + ** + * Parses given transform string into an array of transformations + - TString (string|array) transform string or array of transformations (in the last case it is returned straight away) + = (array) array of transformations +\*/ +var parseTransformString = Snap.parseTransformString = function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (is(TString, "array") && is(TString[0], "array")) { // rough assumption + data = Snap.path.clone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b].concat(params)); + }); + } + data.toString = Snap.path.toString; + return data; +}; +function svgTransform2string(tstr) { + var res = []; + tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) { + params = params.split(/\s*,\s*|\s+/); + if (name == "rotate" && params.length == 1) { + params.push(0, 0); + } + if (name == "scale") { + if (params.length > 2) { + params = params.slice(0, 2); + } else if (params.length == 2) { + params.push(0, 0); + } + if (params.length == 1) { + params.push(params[0], 0, 0); + } + } + if (name == "skewX") { + res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]); + } else if (name == "skewY") { + res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]); + } else { + res.push([name.charAt(0)].concat(params)); + } + return all; + }); + return res; +} +Snap._.svgTransform2string = svgTransform2string; +Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i; +function transform2matrix(tstr, bbox) { + var tdata = parseTransformString(tstr), + m = new Snap.Matrix; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 2){ + m.translate(t[1], 0); + } else if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || bbox; + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || bbox; + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.scale(t[1], t[1], x2, y2); + } else { + m.scale(t[1], t[1], t[2], t[3]); + } + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + } + } + return m; +} +Snap._.transform2matrix = transform2matrix; +Snap._unit2px = unit2px; +var contains = glob.doc.contains || glob.doc.compareDocumentPosition ? + function (a, b) { + var adown = a.nodeType == 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a == bup || !!(bup && bup.nodeType == 1 && ( + adown.contains ? + adown.contains(bup) : + a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16 + )); + } : + function (a, b) { + if (b) { + while (b) { + b = b.parentNode; + if (b == a) { + return true; + } + } + } + return false; + }; +function getSomeDefs(el) { + var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) || + (el.node.parentNode && wrap(el.node.parentNode)) || + Snap.select("svg") || + Snap(0, 0), + pdefs = p.select("defs"), + defs = pdefs == null ? false : pdefs.node; + if (!defs) { + defs = make("defs", p.node).node; + } + return defs; +} +function getSomeSVG(el) { + return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg"); +} +Snap._.getSomeDefs = getSomeDefs; +Snap._.getSomeSVG = getSomeSVG; +function unit2px(el, name, value) { + var svg = getSomeSVG(el).node, + out = {}, + mgr = svg.querySelector(".svg---mgr"); + if (!mgr) { + mgr = $("rect"); + $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"}); + svg.appendChild(mgr); + } + function getW(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {width: val}); + try { + return mgr.getBBox().width; + } catch (e) { + return 0; + } + } + function getH(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {height: val}); + try { + return mgr.getBBox().height; + } catch (e) { + return 0; + } + } + function set(nam, f) { + if (name == null) { + out[nam] = f(el.attr(nam) || 0); + } else if (nam == name) { + out = f(value == null ? el.attr(nam) || 0 : value); + } + } + switch (el.type) { + case "rect": + set("rx", getW); + set("ry", getH); + case "image": + set("width", getW); + set("height", getH); + case "text": + set("x", getW); + set("y", getH); + break; + case "circle": + set("cx", getW); + set("cy", getH); + set("r", getW); + break; + case "ellipse": + set("cx", getW); + set("cy", getH); + set("rx", getW); + set("ry", getH); + break; + case "line": + set("x1", getW); + set("x2", getW); + set("y1", getH); + set("y2", getH); + break; + case "marker": + set("refX", getW); + set("markerWidth", getW); + set("refY", getH); + set("markerHeight", getH); + break; + case "radialGradient": + set("fx", getW); + set("fy", getH); + break; + case "tspan": + set("dx", getW); + set("dy", getH); + break; + default: + set(name, getW); + } + svg.removeChild(mgr); + return out; +} +/*\ + * Snap.select + [ method ] + ** + * Wraps a DOM element specified by CSS selector as @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.select = function (query) { + query = Str(query).replace(/([^\\]):/g, "$1\\:"); + return wrap(glob.doc.querySelector(query)); +}; +/*\ + * Snap.selectAll + [ method ] + ** + * Wraps DOM elements specified by CSS selector as set or array of @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.selectAll = function (query) { + var nodelist = glob.doc.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; +}; + +function add2group(list) { + if (!is(list, "array")) { + list = Array.prototype.slice.call(arguments, 0); + } + var i = 0, + j = 0, + node = this.node; + while (this[i]) delete this[i++]; + for (i = 0; i < list.length; i++) { + if (list[i].type == "set") { + list[i].forEach(function (el) { + node.appendChild(el.node); + }); + } else { + node.appendChild(list[i].node); + } + } + var children = node.childNodes; + for (i = 0; i < children.length; i++) { + this[j++] = wrap(children[i]); + } + return this; +} +// Hub garbage collector every 10s +setInterval(function () { + for (var key in hub) if (hub[has](key)) { + var el = hub[key], + node = el.node; + if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) { + delete hub[key]; + } + } +}, 1e4); +function Element(el) { + if (el.snap in hub) { + return hub[el.snap]; + } + var svg; + try { + svg = el.ownerSVGElement; + } catch(e) {} + /*\ + * Element.node + [ property (object) ] + ** + * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. + > Usage + | // draw a circle at coordinate 10,10 with radius of 10 + | var c = paper.circle(10, 10, 10); + | c.node.onclick = function () { + | c.attr("fill", "red"); + | }; + \*/ + this.node = el; + if (svg) { + this.paper = new Paper(svg); + } + /*\ + * Element.type + [ property (string) ] + ** + * SVG tag name of the given element. + \*/ + this.type = el.tagName || el.nodeName; + var id = this.id = ID(this); + this.anims = {}; + this._ = { + transform: [] + }; + el.snap = id; + hub[id] = this; + if (this.type == "g") { + this.add = add2group; + } + if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) { + for (var method in Paper.prototype) if (Paper.prototype[has](method)) { + this[method] = Paper.prototype[method]; + } + } +} + /*\ + * Element.attr + [ method ] + ** + * Gets or sets given attributes of the element. + ** + - params (object) contains key-value pairs of attributes you want to set + * or + - param (string) name of the attribute + = (Element) the current element + * or + = (string) value of attribute + > Usage + | el.attr({ + | fill: "#fc0", + | stroke: "#000", + | strokeWidth: 2, // CamelCase... + | "fill-opacity": 0.5, // or dash-separated names + | width: "*=2" // prefixed values + | }); + | console.log(el.attr("fill")); // #fc0 + * Prefixed values in format `"+=10"` supported. All four operations + * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+` + * and `-`: `"+=2em"`. + \*/ + Element.prototype.attr = function (params, value) { + var el = this, + node = el.node; + if (!params) { + if (node.nodeType != 1) { + return { + text: node.nodeValue + }; + } + var attr = node.attributes, + out = {}; + for (var i = 0, ii = attr.length; i < ii; i++) { + out[attr[i].nodeName] = attr[i].nodeValue; + } + return out; + } + if (is(params, "string")) { + if (arguments.length > 1) { + var json = {}; + json[params] = value; + params = json; + } else { + return eve("snap.util.getattr." + params, el).firstDefined(); + } + } + for (var att in params) { + if (params[has](att)) { + eve("snap.util.attr." + att, el, params[att]); + } + } + return el; + }; +/*\ + * Snap.parse + [ method ] + ** + * Parses SVG fragment and converts it into a @Fragment + ** + - svg (string) SVG string + = (Fragment) the @Fragment +\*/ +Snap.parse = function (svg) { + var f = glob.doc.createDocumentFragment(), + full = true, + div = glob.doc.createElement("div"); + svg = Str(svg); + if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) { + svg = "<svg>" + svg + "</svg>"; + full = false; + } + div.innerHTML = svg; + svg = div.getElementsByTagName("svg")[0]; + if (svg) { + if (full) { + f = svg; + } else { + while (svg.firstChild) { + f.appendChild(svg.firstChild); + } + } + } + return new Fragment(f); +}; +function Fragment(frag) { + this.node = frag; +} +/*\ + * Snap.fragment + [ method ] + ** + * Creates a DOM fragment from a given list of elements or strings + ** + - varargs (…) SVG string + = (Fragment) the @Fragment +\*/ +Snap.fragment = function () { + var args = Array.prototype.slice.call(arguments, 0), + f = glob.doc.createDocumentFragment(); + for (var i = 0, ii = args.length; i < ii; i++) { + var item = args[i]; + if (item.node && item.node.nodeType) { + f.appendChild(item.node); + } + if (item.nodeType) { + f.appendChild(item); + } + if (typeof item == "string") { + f.appendChild(Snap.parse(item).node); + } + } + return new Fragment(f); +}; + +function make(name, parent) { + var res = $(name); + parent.appendChild(res); + var el = wrap(res); + return el; +} +function Paper(w, h) { + var res, + desc, + defs, + proto = Paper.prototype; + if (w && w.tagName == "svg") { + if (w.snap in hub) { + return hub[w.snap]; + } + var doc = w.ownerDocument; + res = new Element(w); + desc = w.getElementsByTagName("desc")[0]; + defs = w.getElementsByTagName("defs")[0]; + if (!desc) { + desc = $("desc"); + desc.appendChild(doc.createTextNode("Created with Snap")); + res.node.appendChild(desc); + } + if (!defs) { + defs = $("defs"); + res.node.appendChild(defs); + } + res.defs = defs; + for (var key in proto) if (proto[has](key)) { + res[key] = proto[key]; + } + res.paper = res.root = res; + } else { + res = make("svg", glob.doc.body); + $(res.node, { + height: h, + version: 1.1, + width: w, + xmlns: xmlns + }); + } + return res; +} +function wrap(dom) { + if (!dom) { + return dom; + } + if (dom instanceof Element || dom instanceof Fragment) { + return dom; + } + if (dom.tagName && dom.tagName.toLowerCase() == "svg") { + return new Paper(dom); + } + if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") { + return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]); + } + return new Element(dom); +} + +Snap._.make = make; +Snap._.wrap = wrap; +/*\ + * Paper.el + [ method ] + ** + * Creates an element on paper with a given name and no attributes + ** + - name (string) tag name + - attr (object) attributes + = (Element) the current element + > Usage + | var c = paper.circle(10, 10, 10); // is the same as... + | var c = paper.el("circle").attr({ + | cx: 10, + | cy: 10, + | r: 10 + | }); + | // and the same as + | var c = paper.el("circle", { + | cx: 10, + | cy: 10, + | r: 10 + | }); +\*/ +Paper.prototype.el = function (name, attr) { + var el = make(name, this.node); + attr && el.attr(attr); + return el; +}; +/*\ + * Element.children + [ method ] + ** + * Returns array of all the children of the element. + = (array) array of Elements +\*/ +Element.prototype.children = function () { + var out = [], + ch = this.node.childNodes; + for (var i = 0, ii = ch.length; i < ii; i++) { + out[i] = Snap(ch[i]); + } + return out; +}; +function jsonFiller(root, o) { + for (var i = 0, ii = root.length; i < ii; i++) { + var item = { + type: root[i].type, + attr: root[i].attr() + }, + children = root[i].children(); + o.push(item); + if (children.length) { + jsonFiller(children, item.childNodes = []); + } + } +} +/*\ + * Element.toJSON + [ method ] + ** + * Returns object representation of the given element and all its children. + = (object) in format + o { + o type (string) this.type, + o attr (object) attributes map, + o childNodes (array) optional array of children in the same format + o } +\*/ +Element.prototype.toJSON = function () { + var out = []; + jsonFiller([this], out); + return out[0]; +}; +// default +eve.on("snap.util.getattr", function () { + var att = eve.nt(); + att = att.substring(att.lastIndexOf(".") + 1); + var css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css); + } else { + return $(this.node, att); + } +}); +var cssAttr = { + "alignment-baseline": 0, + "baseline-shift": 0, + "clip": 0, + "clip-path": 0, + "clip-rule": 0, + "color": 0, + "color-interpolation": 0, + "color-interpolation-filters": 0, + "color-profile": 0, + "color-rendering": 0, + "cursor": 0, + "direction": 0, + "display": 0, + "dominant-baseline": 0, + "enable-background": 0, + "fill": 0, + "fill-opacity": 0, + "fill-rule": 0, + "filter": 0, + "flood-color": 0, + "flood-opacity": 0, + "font": 0, + "font-family": 0, + "font-size": 0, + "font-size-adjust": 0, + "font-stretch": 0, + "font-style": 0, + "font-variant": 0, + "font-weight": 0, + "glyph-orientation-horizontal": 0, + "glyph-orientation-vertical": 0, + "image-rendering": 0, + "kerning": 0, + "letter-spacing": 0, + "lighting-color": 0, + "marker": 0, + "marker-end": 0, + "marker-mid": 0, + "marker-start": 0, + "mask": 0, + "opacity": 0, + "overflow": 0, + "pointer-events": 0, + "shape-rendering": 0, + "stop-color": 0, + "stop-opacity": 0, + "stroke": 0, + "stroke-dasharray": 0, + "stroke-dashoffset": 0, + "stroke-linecap": 0, + "stroke-linejoin": 0, + "stroke-miterlimit": 0, + "stroke-opacity": 0, + "stroke-width": 0, + "text-anchor": 0, + "text-decoration": 0, + "text-rendering": 0, + "unicode-bidi": 0, + "visibility": 0, + "word-spacing": 0, + "writing-mode": 0 +}; + +eve.on("snap.util.attr", function (value) { + var att = eve.nt(), + attr = {}; + att = att.substring(att.lastIndexOf(".") + 1); + attr[att] = value; + var style = att.replace(/-(\w)/gi, function (all, letter) { + return letter.toUpperCase(); + }), + css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + this.node.style[style] = value == null ? E : value; + } else { + $(this.node, attr); + } +}); +(function (proto) {}(Paper.prototype)); + +// simple ajax +/*\ + * Snap.ajax + [ method ] + ** + * Simple implementation of Ajax + ** + - url (string) URL + - postData (object|string) data for post request + - callback (function) callback + - scope (object) #optional scope of callback + * or + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback + = (XMLHttpRequest) the XMLHttpRequest object, just in case +\*/ +Snap.ajax = function (url, postData, callback, scope){ + var req = new XMLHttpRequest, + id = ID(); + if (req) { + if (is(postData, "function")) { + scope = callback; + callback = postData; + postData = null; + } else if (is(postData, "object")) { + var pd = []; + for (var key in postData) if (postData.hasOwnProperty(key)) { + pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key])); + } + postData = pd.join("&"); + } + req.open((postData ? "POST" : "GET"), url, true); + if (postData) { + req.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + if (callback) { + eve.once("snap.ajax." + id + ".0", callback); + eve.once("snap.ajax." + id + ".200", callback); + eve.once("snap.ajax." + id + ".304", callback); + } + req.onreadystatechange = function() { + if (req.readyState != 4) return; + eve("snap.ajax." + id + "." + req.status, scope, req); + }; + if (req.readyState == 4) { + return req; + } + req.send(postData); + return req; + } +}; +/*\ + * Snap.load + [ method ] + ** + * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX) + ** + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback +\*/ +Snap.load = function (url, callback, scope) { + Snap.ajax(url, function (req) { + var f = Snap.parse(req.responseText); + scope ? callback.call(scope, f) : callback(f); + }); +}; +var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; +}; +/*\ + * Snap.getElementByPoint + [ method ] + ** + * Returns you topmost element under given point. + ** + = (object) Snap element object + - x (number) x coordinate from the top left corner of the window + - y (number) y coordinate from the top left corner of the window + > Usage + | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); +\*/ +Snap.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = glob.doc.elementFromPoint(x, y); + if (glob.win.opera && target.tagName == "svg") { + var so = getOffset(target), + sr = target.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = target.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + return wrap(target); +}; +/*\ + * Snap.plugin + [ method ] + ** + * Let you write plugins. You pass in a function with five arguments, like this: + | Snap.plugin(function (Snap, Element, Paper, global, Fragment) { + | Snap.newmethod = function () {}; + | Element.prototype.newmethod = function () {}; + | Paper.prototype.newmethod = function () {}; + | }); + * Inside the function you have access to all main objects (and their + * prototypes). This allow you to extend anything you want. + ** + - f (function) your plugin body +\*/ +Snap.plugin = function (f) { + f(Snap, Element, Paper, glob, Fragment); +}; +glob.win.Snap = Snap; +return Snap; +}(window || this)); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var elproto = Element.prototype, + is = Snap.is, + Str = String, + unit2px = Snap._unit2px, + $ = Snap._.$, + make = Snap._.make, + getSomeDefs = Snap._.getSomeDefs, + has = "hasOwnProperty", + wrap = Snap._.wrap; + /*\ + * Element.getBBox + [ method ] + ** + * Returns the bounding box descriptor for the given element + ** + = (object) bounding box descriptor: + o { + o cx: (number) x of the center, + o cy: (number) x of the center, + o h: (number) height, + o height: (number) height, + o path: (string) path command for the box, + o r0: (number) radius of a circle that fully encloses the box, + o r1: (number) radius of the smallest circle that can be enclosed, + o r2: (number) radius of the largest circle that can be enclosed, + o vb: (string) box as a viewbox command, + o w: (number) width, + o width: (number) width, + o x2: (number) x of the right side, + o x: (number) x of the left side, + o y2: (number) y of the bottom edge, + o y: (number) y of the top edge + o } + \*/ + elproto.getBBox = function (isWithoutTransform) { + if (!Snap.Matrix || !Snap.path) { + return this.node.getBBox(); + } + var el = this, + m = new Snap.Matrix; + if (el.removed) { + return Snap._.box(); + } + while (el.type == "use") { + if (!isWithoutTransform) { + m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0)); + } + if (el.original) { + el = el.original; + } else { + var href = el.attr("xlink:href"); + el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1)); + } + } + var _ = el._, + pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt; + try { + if (isWithoutTransform) { + _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox()); + return Snap._.box(_.bboxwt); + } else { + el.realPath = pathfinder(el); + el.matrix = el.transform().localMatrix; + _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix))); + return Snap._.box(_.bbox); + } + } catch (e) { + // Firefox doesn’t give you bbox of hidden element + return Snap._.box(); + } + }; + var propString = function () { + return this.string; + }; + function extractTransform(el, tstr) { + if (tstr == null) { + var doReturn = true; + if (el.type == "linearGradient" || el.type == "radialGradient") { + tstr = el.node.getAttribute("gradientTransform"); + } else if (el.type == "pattern") { + tstr = el.node.getAttribute("patternTransform"); + } else { + tstr = el.node.getAttribute("transform"); + } + if (!tstr) { + return new Snap.Matrix; + } + tstr = Snap._.svgTransform2string(tstr); + } else { + if (!Snap._.rgTransform.test(tstr)) { + tstr = Snap._.svgTransform2string(tstr); + } else { + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || ""); + } + if (is(tstr, "array")) { + tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr); + } + el._.transform = tstr; + } + var m = Snap._.transform2matrix(tstr, el.getBBox(1)); + if (doReturn) { + return m; + } else { + el.matrix = m; + } + } + /*\ + * Element.transform + [ method ] + ** + * Gets or sets transformation of the element + ** + - tstr (string) transform string in Snap or SVG format + = (Element) the current element + * or + = (object) transformation descriptor: + o { + o string (string) transform string, + o globalMatrix (Matrix) matrix of all transformations applied to element or its parents, + o localMatrix (Matrix) matrix of transformations applied only to the element, + o diffMatrix (Matrix) matrix of difference between global and local transformations, + o global (string) global transformation as string, + o local (string) local transformation as string, + o toString (function) returns `string` property + o } + \*/ + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + var papa = this, + global = new Snap.Matrix(this.node.getCTM()), + local = extractTransform(this), + ms = [local], + m = new Snap.Matrix, + i, + localString = local.toTransformString(), + string = Str(local) == Str(this.matrix) ? + Str(_.transform) : localString; + while (papa.type != "svg" && (papa = papa.parent())) { + ms.push(extractTransform(papa)); + } + i = ms.length; + while (i--) { + m.add(ms[i]); + } + return { + string: string, + globalMatrix: global, + totalMatrix: m, + localMatrix: local, + diffMatrix: global.clone().add(local.invert()), + global: global.toTransformString(), + total: m.toTransformString(), + local: localString, + toString: propString + }; + } + if (tstr instanceof Snap.Matrix) { + this.matrix = tstr; + this._.transform = tstr.toTransformString(); + } else { + extractTransform(this, tstr); + } + + if (this.node) { + if (this.type == "linearGradient" || this.type == "radialGradient") { + $(this.node, {gradientTransform: this.matrix}); + } else if (this.type == "pattern") { + $(this.node, {patternTransform: this.matrix}); + } else { + $(this.node, {transform: this.matrix}); + } + } + + return this; + }; + /*\ + * Element.parent + [ method ] + ** + * Returns the element's parent + ** + = (Element) the parent element + \*/ + elproto.parent = function () { + return wrap(this.node.parentNode); + }; + /*\ + * Element.append + [ method ] + ** + * Appends the given element to current one + ** + - el (Element|Set) element to append + = (Element) the parent element + \*/ + /*\ + * Element.add + [ method ] + ** + * See @Element.append + \*/ + elproto.append = elproto.add = function (el) { + if (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + it.add(el); + }); + return this; + } + el = wrap(el); + this.node.appendChild(el.node); + el.paper = this.paper; + } + return this; + }; + /*\ + * Element.appendTo + [ method ] + ** + * Appends the current element to the given one + ** + - el (Element) parent element to append to + = (Element) the child element + \*/ + elproto.appendTo = function (el) { + if (el) { + el = wrap(el); + el.append(this); + } + return this; + }; + /*\ + * Element.prepend + [ method ] + ** + * Prepends the given element to the current one + ** + - el (Element) element to prepend + = (Element) the parent element + \*/ + elproto.prepend = function (el) { + if (el) { + if (el.type == "set") { + var it = this, + first; + el.forEach(function (el) { + if (first) { + first.after(el); + } else { + it.prepend(el); + } + first = el; + }); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.insertBefore(el.node, this.node.firstChild); + this.add && this.add(); + el.paper = this.paper; + this.parent() && this.parent().add(); + parent && parent.add(); + } + return this; + }; + /*\ + * Element.prependTo + [ method ] + ** + * Prepends the current element to the given one + ** + - el (Element) parent element to prepend to + = (Element) the child element + \*/ + elproto.prependTo = function (el) { + el = wrap(el); + el.prepend(this); + return this; + }; + /*\ + * Element.before + [ method ] + ** + * Inserts given element before the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.before = function (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + var parent = el.parent(); + it.node.parentNode.insertBefore(el.node, it.node); + parent && parent.add(); + }); + this.parent().add(); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.parentNode.insertBefore(el.node, this.node); + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.after + [ method ] + ** + * Inserts given element after the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.after = function (el) { + el = wrap(el); + var parent = el.parent(); + if (this.node.nextSibling) { + this.node.parentNode.insertBefore(el.node, this.node.nextSibling); + } else { + this.node.parentNode.appendChild(el.node); + } + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.insertBefore + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertBefore = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.insertAfter + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertAfter = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node.nextSibling); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.remove + [ method ] + ** + * Removes element from the DOM + = (Element) the detached element + \*/ + elproto.remove = function () { + var parent = this.parent(); + this.node.parentNode && this.node.parentNode.removeChild(this.node); + delete this.paper; + this.removed = true; + parent && parent.add(); + return this; + }; + /*\ + * Element.select + [ method ] + ** + * Gathers the nested @Element matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Element) result of query selection + \*/ + elproto.select = function (query) { + return wrap(this.node.querySelector(query)); + }; + /*\ + * Element.selectAll + [ method ] + ** + * Gathers nested @Element objects matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Set|array) result of query selection + \*/ + elproto.selectAll = function (query) { + var nodelist = this.node.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; + }; + /*\ + * Element.asPX + [ method ] + ** + * Returns given attribute of the element as a `px` value (not %, em, etc.) + ** + - attr (string) attribute name + - value (string) #optional attribute value + = (Element) result of query selection + \*/ + elproto.asPX = function (attr, value) { + if (value == null) { + value = this.attr(attr); + } + return +unit2px(this, attr, value); + }; + // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar. + /*\ + * Element.use + [ method ] + ** + * Creates a `<use>` element linked to the current element + ** + = (Element) the `<use>` element + \*/ + elproto.use = function () { + var use, + id = this.node.id; + if (!id) { + id = this.id; + $(this.node, { + id: id + }); + } + if (this.type == "linearGradient" || this.type == "radialGradient" || + this.type == "pattern") { + use = make(this.type, this.node.parentNode); + } else { + use = make("use", this.node.parentNode); + } + $(use.node, { + "xlink:href": "#" + id + }); + use.original = this; + return use; + }; + function fixids(el) { + var els = el.selectAll("*"), + it, + url = /^\s*url\(("|'|)(.*)\1\)\s*$/, + ids = [], + uses = {}; + function urltest(it, name) { + var val = $(it.node, name); + val = val && val.match(url); + val = val && val[2]; + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + var attr = {}; + attr[name] = URL(id); + $(it.node, attr); + }); + } + } + function linktest(it) { + var val = $(it.node, "xlink:href"); + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + it.attr("xlink:href", "#" + id); + }); + } + } + for (var i = 0, ii = els.length; i < ii; i++) { + it = els[i]; + urltest(it, "fill"); + urltest(it, "stroke"); + urltest(it, "filter"); + urltest(it, "mask"); + urltest(it, "clip-path"); + linktest(it); + var oldid = $(it.node, "id"); + if (oldid) { + $(it.node, {id: it.id}); + ids.push({ + old: oldid, + id: it.id + }); + } + } + for (i = 0, ii = ids.length; i < ii; i++) { + var fs = uses[ids[i].old]; + if (fs) { + for (var j = 0, jj = fs.length; j < jj; j++) { + fs[j](ids[i].id); + } + } + } + } + /*\ + * Element.clone + [ method ] + ** + * Creates a clone of the element and inserts it after the element + ** + = (Element) the clone + \*/ + elproto.clone = function () { + var clone = wrap(this.node.cloneNode(true)); + if ($(clone.node, "id")) { + $(clone.node, {id: clone.id}); + } + fixids(clone); + clone.insertAfter(this); + return clone; + }; + /*\ + * Element.toDefs + [ method ] + ** + * Moves element to the shared `<defs>` area + ** + = (Element) the element + \*/ + elproto.toDefs = function () { + var defs = getSomeDefs(this); + defs.appendChild(this.node); + return this; + }; + /*\ + * Element.toPattern + [ method ] + ** + * Creates a `<pattern>` element from the current element + ** + * To create a pattern you have to specify the pattern rect: + - x (string|number) + - y (string|number) + - width (string|number) + - height (string|number) + = (Element) the `<pattern>` element + * You can use pattern later on as an argument for `fill` attribute: + | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({ + | fill: "none", + | stroke: "#bada55", + | strokeWidth: 5 + | }).pattern(0, 0, 10, 10), + | c = paper.circle(200, 200, 100); + | c.attr({ + | fill: p + | }); + \*/ + elproto.pattern = elproto.toPattern = function (x, y, width, height) { + var p = make("pattern", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + $(p.node, { + x: x, + y: y, + width: width, + height: height, + patternUnits: "userSpaceOnUse", + id: p.id, + viewBox: [x, y, width, height].join(" ") + }); + p.node.appendChild(this.node); + return p; + }; +// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path. +// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values? + /*\ + * Element.marker + [ method ] + ** + * Creates a `<marker>` element from the current element + ** + * To create a marker you have to specify the bounding rect and reference point: + - x (number) + - y (number) + - width (number) + - height (number) + - refX (number) + - refY (number) + = (Element) the `<marker>` element + * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end. + \*/ + // TODO add usage for markers + elproto.marker = function (x, y, width, height, refX, refY) { + var p = make("marker", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + refX = x.refX || x.cx; + refY = x.refY || x.cy; + x = x.x; + } + $(p.node, { + viewBox: [x, y, width, height].join(" "), + markerWidth: width, + markerHeight: height, + orient: "auto", + refX: refX || 0, + refY: refY || 0, + id: p.id + }); + p.node.appendChild(this.node); + return p; + }; + // animation + function slice(from, to, f) { + return function (arr) { + var res = arr.slice(from, to); + if (res.length == 1) { + res = res[0]; + } + return f ? f(res) : res; + }; + } + var Animation = function (attr, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + this.attr = attr; + this.dur = ms; + easing && (this.easing = easing); + callback && (this.callback = callback); + }; + Snap._.Animation = Animation; + /*\ + * Snap.animation + [ method ] + ** + * Creates an animation object + ** + - attr (object) attributes of final destination + - duration (number) duration of the animation, in milliseconds + - easing (function) #optional one of easing functions of @mina or custom one + - callback (function) #optional callback function that fires when animation ends + = (object) animation object + \*/ + Snap.animation = function (attr, ms, easing, callback) { + return new Animation(attr, ms, easing, callback); + }; + /*\ + * Element.inAnim + [ method ] + ** + * Returns a set of animations that may be able to manipulate the current element + ** + = (object) in format: + o { + o anim (object) animation object, + o mina (object) @mina object, + o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + \*/ + elproto.inAnim = function () { + var el = this, + res = []; + for (var id in el.anims) if (el.anims[has](id)) { + (function (a) { + res.push({ + anim: new Animation(a._attrs, a.dur, a.easing, a._callback), + mina: a, + curStatus: a.status(), + status: function (val) { + return a.status(val); + }, + stop: function () { + a.stop(); + } + }); + }(el.anims[id])); + } + return res; + }; + /*\ + * Snap.animate + [ method ] + ** + * Runs generic animation of one number into another with a caring function + ** + - from (number|array) number or array of numbers + - to (number|array) number or array of numbers + - setter (function) caring function that accepts one number argument + - duration (number) duration, in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function to execute when animation ends + = (object) animation object in @mina format + o { + o id (string) animation id, consider it read-only, + o duration (function) gets or sets the duration of the animation, + o easing (function) easing, + o speed (function) gets or sets the speed of the animation, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + | var rect = Snap().rect(0, 0, 10, 10); + | Snap.animate(0, 10, function (val) { + | rect.attr({ + | x: val + | }); + | }, 1000); + | // in given context is equivalent to + | rect.animate({x: 10}, 1000); + \*/ + Snap.animate = function (from, to, setter, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + var now = mina.time(), + anim = mina(from, to, now, now + ms, mina.time, setter, easing); + callback && eve.once("mina.finish." + anim.id, callback); + return anim; + }; + /*\ + * Element.stop + [ method ] + ** + * Stops all the animations for the current element + ** + = (Element) the current element + \*/ + elproto.stop = function () { + var anims = this.inAnim(); + for (var i = 0, ii = anims.length; i < ii; i++) { + anims[i].stop(); + } + return this; + }; + /*\ + * Element.animate + [ method ] + ** + * Animates the given attributes of the element + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + = (Element) the current element + \*/ + elproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = attrs.dur; + attrs = attrs.attr; + } + var fkeys = [], tkeys = [], keys = {}, from, to, f, eq, + el = this; + for (var key in attrs) if (attrs[has](key)) { + if (el.equal) { + eq = el.equal(key, Str(attrs[key])); + from = eq.from; + to = eq.to; + f = eq.f; + } else { + from = +el.attr(key); + to = +attrs[key]; + } + var len = is(from, "array") ? from.length : 1; + keys[key] = slice(fkeys.length, fkeys.length + len, f); + fkeys = fkeys.concat(from); + tkeys = tkeys.concat(to); + } + var now = mina.time(), + anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) { + var attr = {}; + for (var key in keys) if (keys[has](key)) { + attr[key] = keys[key](val); + } + el.attr(attr); + }, easing); + el.anims[anim.id] = anim; + anim._attrs = attrs; + anim._callback = callback; + eve("snap.animcreated." + el.id, anim); + eve.once("mina.finish." + anim.id, function () { + delete el.anims[anim.id]; + callback && callback.call(el); + }); + eve.once("mina.stop." + anim.id, function () { + delete el.anims[anim.id]; + }); + return el; + }; + var eldata = {}; + /*\ + * Element.data + [ method ] + ** + * Adds or retrieves given value associated with given key. (Don’t confuse + * with `data-` attributes) + * + * See also @Element.removeData + - key (string) key to store data + - value (any) #optional value to store + = (object) @Element + * or, if value is not specified: + = (any) value + > Usage + | for (var i = 0, i < 5, i++) { + | paper.circle(10 + 15 * i, 10, 10) + | .attr({fill: "#000"}) + | .data("i", i) + | .click(function () { + | alert(this.data("i")); + | }); + | } + \*/ + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 0){ + eve("snap.data.get." + this.id, this, data, null); + return data; + } + if (arguments.length == 1) { + if (Snap.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("snap.data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("snap.data.set." + this.id, this, value, key); + return this; + }; + /*\ + * Element.removeData + [ method ] + ** + * Removes value associated with an element by given key. + * If key is not provided, removes all the data of the element. + - key (string) #optional key + = (object) @Element + \*/ + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + /*\ + * Element.outerSVG + [ method ] + ** + * Returns SVG code for the element, equivalent to HTML's `outerHTML`. + * + * See also @Element.innerSVG + = (string) SVG code for the element + \*/ + /*\ + * Element.toString + [ method ] + ** + * See @Element.outerSVG + \*/ + elproto.outerSVG = elproto.toString = toString(1); + /*\ + * Element.innerSVG + [ method ] + ** + * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML` + = (string) SVG code for the element + \*/ + elproto.innerSVG = toString(); + function toString(type) { + return function () { + var res = type ? "<" + this.type : "", + attr = this.node.attributes, + chld = this.node.childNodes; + if (type) { + for (var i = 0, ii = attr.length; i < ii; i++) { + res += " " + attr[i].name + '="' + + attr[i].value.replace(/"/g, '\\"') + '"'; + } + } + if (chld.length) { + type && (res += ">"); + for (i = 0, ii = chld.length; i < ii; i++) { + if (chld[i].nodeType == 3) { + res += chld[i].nodeValue; + } else if (chld[i].nodeType == 1) { + res += wrap(chld[i]).toString(); + } + } + type && (res += "</" + this.type + ">"); + } else { + type && (res += "/>"); + } + return res; + }; + } + elproto.toDataURL = function () { + if (window && window.btoa) { + var bb = this.getBBox(), + svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', { + x: +bb.x.toFixed(3), + y: +bb.y.toFixed(3), + width: +bb.width.toFixed(3), + height: +bb.height.toFixed(3), + contents: this.outerSVG() + }); + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg))); + } + }; + /*\ + * Fragment.select + [ method ] + ** + * See @Element.select + \*/ + Fragment.prototype.select = elproto.select; + /*\ + * Fragment.selectAll + [ method ] + ** + * See @Element.selectAll + \*/ + Fragment.prototype.selectAll = elproto.selectAll; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var objectToString = Object.prototype.toString, + Str = String, + math = Math, + E = ""; + function Matrix(a, b, c, d, e, f) { + if (b == null && objectToString.call(a) == "[object SVGMatrix]") { + this.a = a.a; + this.b = a.b; + this.c = a.c; + this.d = a.d; + this.e = a.e; + this.f = a.f; + return; + } + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + /*\ + * Matrix.add + [ method ] + ** + * Adds the given matrix to existing one + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - matrix (object) @Matrix + \*/ + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + return this; + }; + /*\ + * Matrix.invert + [ method ] + ** + * Returns an inverted version of the matrix + = (object) @Matrix + \*/ + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + /*\ + * Matrix.clone + [ method ] + ** + * Returns a copy of the matrix + = (object) @Matrix + \*/ + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + /*\ + * Matrix.translate + [ method ] + ** + * Translate the matrix + - x (number) horizontal offset distance + - y (number) vertical offset distance + \*/ + matrixproto.translate = function (x, y) { + return this.add(1, 0, 0, 1, x, y); + }; + /*\ + * Matrix.scale + [ method ] + ** + * Scales the matrix + - x (number) amount to be scaled, with `1` resulting in no change + - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.) + - cx (number) #optional horizontal origin point from which to scale + - cy (number) #optional vertical origin point from which to scale + * Default cx, cy is the middle point of the element. + \*/ + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + return this; + }; + /*\ + * Matrix.rotate + [ method ] + ** + * Rotates the matrix + - a (number) angle of rotation, in degrees + - x (number) horizontal origin point from which to rotate + - y (number) vertical origin point from which to rotate + \*/ + matrixproto.rotate = function (a, x, y) { + a = Snap.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + return this.add(1, 0, 0, 1, -x, -y); + }; + /*\ + * Matrix.x + [ method ] + ** + * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y + - x (number) + - y (number) + = (number) x + \*/ + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + /*\ + * Matrix.y + [ method ] + ** + * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x + - x (number) + - y (number) + = (number) y + \*/ + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + /*\ + * Matrix.determinant + [ method ] + ** + * Finds determinant of the given matrix. + = (number) determinant + \*/ + matrixproto.determinant = function () { + return this.a * this.d - this.b * this.c; + }; + /*\ + * Matrix.split + [ method ] + ** + * Splits matrix into primitive transformations + = (object) in format: + o dx (number) translation by x + o dy (number) translation by y + o scalex (number) scale by x + o scaley (number) scale by y + o shear (number) shear + o rotate (number) rotation in deg + o isSimple (boolean) could it be represented via simple transformations + \*/ + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + if (this.determinant() < 0) { + out.scalex = -out.scalex; + } + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = Snap.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = Snap.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + /*\ + * Matrix.toTransformString + [ method ] + ** + * Returns transform string that represents given matrix + = (string) transform string + \*/ + matrixproto.toTransformString = function (shorter) { + var s = shorter || this.split(); + if (!+s.shear.toFixed(9)) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + /*\ + * Snap.Matrix + [ method ] + ** + * Matrix constructor, extend on your own risk. + * To create matrices use @Snap.matrix. + \*/ + Snap.Matrix = Matrix; + /*\ + * Snap.matrix + [ method ] + ** + * Utility method + ** + * Returns a matrix based on the given parameters + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - svgMatrix (SVGMatrix) + = (object) @Matrix + \*/ + Snap.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var has = "hasOwnProperty", + make = Snap._.make, + wrap = Snap._.wrap, + is = Snap.is, + getSomeDefs = Snap._.getSomeDefs, + reURLValue = /^url\(#?([^)]+)\)$/, + $ = Snap._.$, + URL = Snap.url, + Str = String, + separator = Snap._.separator, + E = ""; + // Attributes event handlers + eve.on("snap.util.attr.mask", function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value.type == "mask") { + var mask = value; + } else { + mask = make("mask", getSomeDefs(this)); + mask.node.appendChild(value.node); + } + !mask.node.id && $(mask.node, { + id: mask.id + }); + $(this.node, { + mask: URL(mask.id) + }); + } + }); + (function (clipIt) { + eve.on("snap.util.attr.clip", clipIt); + eve.on("snap.util.attr.clip-path", clipIt); + eve.on("snap.util.attr.clipPath", clipIt); + }(function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value.type == "clipPath") { + var clip = value; + } else { + clip = make("clipPath", getSomeDefs(this)); + clip.node.appendChild(value.node); + !clip.node.id && $(clip.node, { + id: clip.id + }); + } + $(this.node, { + "clip-path": URL(clip.node.id || clip.id) + }); + } + })); + function fillStroke(name) { + return function (value) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1 && + (value.node.firstChild.tagName == "radialGradient" || + value.node.firstChild.tagName == "linearGradient" || + value.node.firstChild.tagName == "pattern")) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value instanceof Element) { + if (value.type == "radialGradient" || value.type == "linearGradient" + || value.type == "pattern") { + if (!value.node.id) { + $(value.node, { + id: value.id + }); + } + var fill = URL(value.node.id); + } else { + fill = value.attr(name); + } + } else { + fill = Snap.color(value); + if (fill.error) { + var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value); + if (grad) { + if (!grad.node.id) { + $(grad.node, { + id: grad.id + }); + } + fill = URL(grad.node.id); + } else { + fill = value; + } + } else { + fill = Str(fill); + } + } + var attrs = {}; + attrs[name] = fill; + $(this.node, attrs); + this.node.style[name] = E; + }; + } + eve.on("snap.util.attr.fill", fillStroke("fill")); + eve.on("snap.util.attr.stroke", fillStroke("stroke")); + var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i; + eve.on("snap.util.grad.parse", function parseGrad(string) { + string = Str(string); + var tokens = string.match(gradrg); + if (!tokens) { + return null; + } + var type = tokens[1], + params = tokens[2], + stops = tokens[3]; + params = params.split(/\s*,\s*/).map(function (el) { + return +el == el ? +el : el; + }); + if (params.length == 1 && params[0] == 0) { + params = []; + } + stops = stops.split("-"); + stops = stops.map(function (el) { + el = el.split(":"); + var out = { + color: el[0] + }; + if (el[1]) { + out.offset = parseFloat(el[1]); + } + return out; + }); + return { + type: type, + params: params, + stops: stops + }; + }); + + eve.on("snap.util.attr.d", function (value) { + eve.stop(); + if (is(value, "array") && is(value[0], "array")) { + value = Snap.path.toString.call(value); + } + value = Str(value); + if (value.match(/[ruo]/i)) { + value = Snap.path.toAbsolute(value); + } + $(this.node, {d: value}); + })(-1); + eve.on("snap.util.attr.#text", function (value) { + eve.stop(); + value = Str(value); + var txt = glob.doc.createTextNode(value); + while (this.node.firstChild) { + this.node.removeChild(this.node.firstChild); + } + this.node.appendChild(txt); + })(-1); + eve.on("snap.util.attr.path", function (value) { + eve.stop(); + this.attr({d: value}); + })(-1); + eve.on("snap.util.attr.class", function (value) { + eve.stop(); + this.node.className.baseVal = value; + })(-1); + eve.on("snap.util.attr.viewBox", function (value) { + var vb; + if (is(value, "object") && "x" in value) { + vb = [value.x, value.y, value.width, value.height].join(" "); + } else if (is(value, "array")) { + vb = value.join(" "); + } else { + vb = value; + } + $(this.node, { + viewBox: vb + }); + eve.stop(); + })(-1); + eve.on("snap.util.attr.transform", function (value) { + this.transform(value); + eve.stop(); + })(-1); + eve.on("snap.util.attr.r", function (value) { + if (this.type == "rect") { + eve.stop(); + $(this.node, { + rx: value, + ry: value + }); + } + })(-1); + eve.on("snap.util.attr.textpath", function (value) { + eve.stop(); + if (this.type == "text") { + var id, tp, node; + if (!value && this.textPath) { + tp = this.textPath; + while (tp.node.firstChild) { + this.node.appendChild(tp.node.firstChild); + } + tp.remove(); + delete this.textPath; + return; + } + if (is(value, "string")) { + var defs = getSomeDefs(this), + path = wrap(defs.parentNode).path(value); + defs.appendChild(path.node); + id = path.id; + path.attr({id: id}); + } else { + value = wrap(value); + if (value instanceof Element) { + id = value.attr("id"); + if (!id) { + id = value.id; + value.attr({id: id}); + } + } + } + if (id) { + tp = this.textPath; + node = this.node; + if (tp) { + tp.attr({"xlink:href": "#" + id}); + } else { + tp = $("textPath", { + "xlink:href": "#" + id + }); + while (node.firstChild) { + tp.appendChild(node.firstChild); + } + node.appendChild(tp); + this.textPath = wrap(tp); + } + } + } + })(-1); + eve.on("snap.util.attr.text", function (value) { + if (this.type == "text") { + var i = 0, + node = this.node, + tuner = function (chunk) { + var out = $("tspan"); + if (is(chunk, "array")) { + for (var i = 0; i < chunk.length; i++) { + out.appendChild(tuner(chunk[i])); + } + } else { + out.appendChild(glob.doc.createTextNode(chunk)); + } + out.normalize && out.normalize(); + return out; + }; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var tuned = tuner(value); + while (tuned.firstChild) { + node.appendChild(tuned.firstChild); + } + } + eve.stop(); + })(-1); + function setFontSize(value) { + eve.stop(); + if (value == +value) { + value += "px"; + } + this.node.style.fontSize = value; + } + eve.on("snap.util.attr.fontSize", setFontSize)(-1); + eve.on("snap.util.attr.font-size", setFontSize)(-1); + + + eve.on("snap.util.getattr.transform", function () { + eve.stop(); + return this.transform(); + })(-1); + eve.on("snap.util.getattr.textpath", function () { + eve.stop(); + return this.textPath; + })(-1); + // Markers + (function () { + function getter(end) { + return function () { + eve.stop(); + var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end); + if (style == "none") { + return style; + } else { + return Snap(glob.doc.getElementById(style.match(reURLValue)[1])); + } + }; + } + function setter(end) { + return function (value) { + eve.stop(); + var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1); + if (value == "" || !value) { + this.node.style[name] = "none"; + return; + } + if (value.type == "marker") { + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + } + this.node.style[name] = URL(id); + return; + } + }; + } + eve.on("snap.util.getattr.marker-end", getter("end"))(-1); + eve.on("snap.util.getattr.markerEnd", getter("end"))(-1); + eve.on("snap.util.getattr.marker-start", getter("start"))(-1); + eve.on("snap.util.getattr.markerStart", getter("start"))(-1); + eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1); + eve.on("snap.util.getattr.markerMid", getter("mid"))(-1); + eve.on("snap.util.attr.marker-end", setter("end"))(-1); + eve.on("snap.util.attr.markerEnd", setter("end"))(-1); + eve.on("snap.util.attr.marker-start", setter("start"))(-1); + eve.on("snap.util.attr.markerStart", setter("start"))(-1); + eve.on("snap.util.attr.marker-mid", setter("mid"))(-1); + eve.on("snap.util.attr.markerMid", setter("mid"))(-1); + }()); + eve.on("snap.util.getattr.r", function () { + if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) { + eve.stop(); + return $(this.node, "rx"); + } + })(-1); + function textExtract(node) { + var out = []; + var children = node.childNodes; + for (var i = 0, ii = children.length; i < ii; i++) { + var chi = children[i]; + if (chi.nodeType == 3) { + out.push(chi.nodeValue); + } + if (chi.tagName == "tspan") { + if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) { + out.push(chi.firstChild.nodeValue); + } else { + out.push(textExtract(chi)); + } + } + } + return out; + } + eve.on("snap.util.getattr.text", function () { + if (this.type == "text" || this.type == "tspan") { + eve.stop(); + var out = textExtract(this.node); + return out.length == 1 ? out[0] : out; + } + })(-1); + eve.on("snap.util.getattr.#text", function () { + return this.node.textContent; + })(-1); + eve.on("snap.util.getattr.viewBox", function () { + eve.stop(); + var vb = $(this.node, "viewBox"); + if (vb) { + vb = vb.split(separator); + return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.points", function () { + var p = $(this.node, "points"); + eve.stop(); + if (p) { + return p.split(separator); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.path", function () { + var p = $(this.node, "d"); + eve.stop(); + return p; + })(-1); + eve.on("snap.util.getattr.class", function () { + return this.node.className.baseVal; + })(-1); + function getFontSize() { + eve.stop(); + return this.node.style.fontSize; + } + eve.on("snap.util.getattr.fontSize", getFontSize)(-1); + eve.on("snap.util.getattr.font-size", getFontSize)(-1); +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var rgNotSpace = /\S+/g, + rgBadSpace = /[\t\r\n\f]/g, + rgTrim = /(^\s+|\s+$)/g, + Str = String, + elproto = Element.prototype; + /*\ + * Element.addClass + [ method ] + ** + * Adds given class name or list of class names to the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.addClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + + if (classes.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (!~pos) { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.removeClass + [ method ] + ** + * Removes given class name or list of class names from the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.removeClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + if (curClasses.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.hasClass + [ method ] + ** + * Checks if the element has a given class name in the list of class names applied to it. + - value (string) class name + ** + = (boolean) `true` if the element has given class + \*/ + elproto.hasClass = function (value) { + var elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || []; + return !!~curClasses.indexOf(value); + }; + /*\ + * Element.toggleClass + [ method ] + ** + * Add or remove one or more classes from the element, depending on either + * the class’s presence or the value of the `flag` argument. + - value (string) class name or space separated list of class names + - flag (boolean) value to determine whether the class should be added or removed + ** + = (Element) original element. + \*/ + elproto.toggleClass = function (value, flag) { + if (flag != null) { + if (flag) { + return this.addClass(value); + } else { + return this.removeClass(value); + } + } + var classes = (value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } else { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var operators = { + "+": function (x, y) { + return x + y; + }, + "-": function (x, y) { + return x - y; + }, + "/": function (x, y) { + return x / y; + }, + "*": function (x, y) { + return x * y; + } + }, + Str = String, + reUnit = /[a-z]+$/i, + reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/; + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + eve.on("snap.util.attr", function (val) { + var plus = Str(val).match(reAddon); + if (plus) { + var evnt = eve.nt(), + name = evnt.substring(evnt.lastIndexOf(".") + 1), + a = this.attr(name), + atr = {}; + eve.stop(); + var unit = plus[3] || "", + aUnit = a.match(reUnit), + op = operators[plus[1]]; + if (aUnit && aUnit == unit) { + val = op(parseFloat(a), +plus[2]); + } else { + a = this.asPX(name); + val = op(this.asPX(name), this.asPX(name, plus[2] + unit)); + } + if (isNaN(a) || isNaN(val)) { + return; + } + atr[name] = val; + this.attr(atr); + } + })(-10); + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this, + bplus = Str(b).match(reAddon); + if (bplus) { + eve.stop(); + var unit = bplus[3] || "", + aUnit = a.match(reUnit), + op = operators[bplus[1]]; + if (aUnit && aUnit == unit) { + return { + from: parseFloat(a), + to: op(parseFloat(a), +bplus[2]), + f: getUnit(aUnit) + }; + } else { + a = this.asPX(name); + return { + from: a, + to: op(a, this.asPX(name, bplus[2] + unit)), + f: getNumber + }; + } + } + })(-10); +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var proto = Paper.prototype, + is = Snap.is; + /*\ + * Paper.rect + [ method ] + * + * Draws a rectangle + ** + - x (number) x coordinate of the top left corner + - y (number) y coordinate of the top left corner + - width (number) width + - height (number) height + - rx (number) #optional horizontal radius for rounded corners, default is 0 + - ry (number) #optional vertical radius for rounded corners, default is rx or 0 + = (object) the `rect` element + ** + > Usage + | // regular rectangle + | var c = paper.rect(10, 10, 50, 50); + | // rectangle with rounded corners + | var c = paper.rect(40, 40, 50, 50, 10); + \*/ + proto.rect = function (x, y, w, h, rx, ry) { + var attr; + if (ry == null) { + ry = rx; + } + if (is(x, "object") && x == "[object Object]") { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + width: w, + height: h + }; + if (rx != null) { + attr.rx = rx; + attr.ry = ry; + } + } + return this.el("rect", attr); + }; + /*\ + * Paper.circle + [ method ] + ** + * Draws a circle + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - r (number) radius + = (object) the `circle` element + ** + > Usage + | var c = paper.circle(50, 50, 40); + \*/ + proto.circle = function (cx, cy, r) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr = { + cx: cx, + cy: cy, + r: r + }; + } + return this.el("circle", attr); + }; + + var preload = (function () { + function onerror() { + this.parentNode.removeChild(this); + } + return function (src, f) { + var img = glob.doc.createElement("img"), + body = glob.doc.body; + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(img); + img.onload = img.onerror = null; + body.removeChild(img); + }; + img.onerror = onerror; + body.appendChild(img); + img.src = src; + }; + }()); + + /*\ + * Paper.image + [ method ] + ** + * Places an image on the surface + ** + - src (string) URI of the source image + - x (number) x offset position + - y (number) y offset position + - width (number) width of the image + - height (number) height of the image + = (object) the `image` element + * or + = (object) Snap element object with type `image` + ** + > Usage + | var c = paper.image("apple.png", 10, 10, 80, 80); + \*/ + proto.image = function (src, x, y, width, height) { + var el = this.el("image"); + if (is(src, "object") && "src" in src) { + el.attr(src); + } else if (src != null) { + var set = { + "xlink:href": src, + preserveAspectRatio: "none" + }; + if (x != null && y != null) { + set.x = x; + set.y = y; + } + if (width != null && height != null) { + set.width = width; + set.height = height; + } else { + preload(src, function () { + Snap._.$(el.node, { + width: this.offsetWidth, + height: this.offsetHeight + }); + }); + } + Snap._.$(el.node, set); + } + return el; + }; + /*\ + * Paper.ellipse + [ method ] + ** + * Draws an ellipse + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - rx (number) horizontal radius + - ry (number) vertical radius + = (object) the `ellipse` element + ** + > Usage + | var c = paper.ellipse(50, 50, 40, 20); + \*/ + proto.ellipse = function (cx, cy, rx, ry) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr ={ + cx: cx, + cy: cy, + rx: rx, + ry: ry + }; + } + return this.el("ellipse", attr); + }; + // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier. + /*\ + * Paper.path + [ method ] + ** + * Creates a `<path>` element using the given string as the path's definition + - pathString (string) #optional path string in SVG format + * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example: + | "M10,20L30,40" + * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates. + * + # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p> + # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> + # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> + # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> + # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> + # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> + # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> + # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> + # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> + # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> + # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> + # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> + # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> + * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier. + * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point. + > Usage + | var c = paper.path("M10 10L90 90"); + | // draw a diagonal line: + | // move to 10,10, line to 90,90 + \*/ + proto.path = function (d) { + var attr; + if (is(d, "object") && !is(d, "array")) { + attr = d; + } else if (d) { + attr = {d: d}; + } + return this.el("path", attr); + }; + /*\ + * Paper.g + [ method ] + ** + * Creates a group element + ** + - varargs (…) #optional elements to nest within the group + = (object) the `g` element + ** + > Usage + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(c2, c1); // note that the order of elements is different + * or + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(); + | g.add(c2, c1); + \*/ + /*\ + * Paper.group + [ method ] + ** + * See @Paper.g + \*/ + proto.group = proto.g = function (first) { + var attr, + el = this.el("g"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.svg + [ method ] + ** + * Creates a nested SVG element. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `svg` element + ** + \*/ + proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) { + var attrs = {}; + if (is(x, "object") && y == null) { + attrs = x; + } else { + if (x != null) { + attrs.x = x; + } + if (y != null) { + attrs.y = y; + } + if (width != null) { + attrs.width = width; + } + if (height != null) { + attrs.height = height; + } + if (vbx != null && vby != null && vbw != null && vbh != null) { + attrs.viewBox = [vbx, vby, vbw, vbh]; + } + } + return this.el("svg", attrs); + }; + /*\ + * Paper.mask + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a mask. + ** + = (object) the `mask` element + ** + \*/ + proto.mask = function (first) { + var attr, + el = this.el("mask"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.ptrn + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a pattern. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `pattern` element + ** + \*/ + proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) { + if (is(x, "object")) { + var attr = x; + } else { + attr = {patternUnits: "userSpaceOnUse"}; + if (x) { + attr.x = x; + } + if (y) { + attr.y = y; + } + if (width != null) { + attr.width = width; + } + if (height != null) { + attr.height = height; + } + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } else { + attr.viewBox = [x || 0, y || 0, width || 0, height || 0]; + } + } + return this.el("pattern", attr); + }; + /*\ + * Paper.use + [ method ] + ** + * Creates a <use> element. + - id (string) @optional id of element to link + * or + - id (Element) @optional element to link + ** + = (object) the `use` element + ** + \*/ + proto.use = function (id) { + if (id != null) { + if (id instanceof Element) { + if (!id.attr("id")) { + id.attr({id: Snap._.id(id)}); + } + id = id.attr("id"); + } + if (String(id).charAt() == "#") { + id = id.substring(1); + } + return this.el("use", {"xlink:href": "#" + id}); + } else { + return Element.prototype.use.call(this); + } + }; + /*\ + * Paper.symbol + [ method ] + ** + * Creates a <symbol> element. + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + = (object) the `symbol` element + ** + \*/ + proto.symbol = function (vx, vy, vw, vh) { + var attr = {}; + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } + + return this.el("symbol", attr); + }; + /*\ + * Paper.text + [ method ] + ** + * Draws a text string + ** + - x (number) x coordinate position + - y (number) y coordinate position + - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements + = (object) the `text` element + ** + > Usage + | var t1 = paper.text(50, 50, "Snap"); + | var t2 = paper.text(50, 50, ["S","n","a","p"]); + | // Text path usage + | t1.attr({textpath: "M10,10L100,100"}); + | // or + | var pth = paper.path("M10,10L100,100"); + | t1.attr({textpath: pth}); + \*/ + proto.text = function (x, y, text) { + var attr = {}; + if (is(x, "object")) { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + text: text || "" + }; + } + return this.el("text", attr); + }; + /*\ + * Paper.line + [ method ] + ** + * Draws a line + ** + - x1 (number) x coordinate position of the start + - y1 (number) y coordinate position of the start + - x2 (number) x coordinate position of the end + - y2 (number) y coordinate position of the end + = (object) the `line` element + ** + > Usage + | var t1 = paper.line(50, 50, 100, 100); + \*/ + proto.line = function (x1, y1, x2, y2) { + var attr = {}; + if (is(x1, "object")) { + attr = x1; + } else if (x1 != null) { + attr = { + x1: x1, + x2: x2, + y1: y1, + y2: y2 + }; + } + return this.el("line", attr); + }; + /*\ + * Paper.polyline + [ method ] + ** + * Draws a polyline + ** + - points (array) array of points + * or + - varargs (…) points + = (object) the `polyline` element + ** + > Usage + | var p1 = paper.polyline([10, 10, 100, 100]); + | var p2 = paper.polyline(10, 10, 100, 100); + \*/ + proto.polyline = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polyline", attr); + }; + /*\ + * Paper.polygon + [ method ] + ** + * Draws a polygon. See @Paper.polyline + \*/ + proto.polygon = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polygon", attr); + }; + // gradients + (function () { + var $ = Snap._.$; + // gradients' helpers + function Gstops() { + return this.selectAll("stop"); + } + function GaddStop(color, offset) { + var stop = $("stop"), + attr = { + offset: +offset + "%" + }; + color = Snap.color(color); + attr["stop-color"] = color.hex; + if (color.opacity < 1) { + attr["stop-opacity"] = color.opacity; + } + $(stop, attr); + this.node.appendChild(stop); + return this; + } + function GgetBBox() { + if (this.type == "linearGradient") { + var x1 = $(this.node, "x1") || 0, + x2 = $(this.node, "x2") || 1, + y1 = $(this.node, "y1") || 0, + y2 = $(this.node, "y2") || 0; + return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1)); + } else { + var cx = this.node.cx || .5, + cy = this.node.cy || .5, + r = this.node.r || 0; + return Snap._.box(cx - r, cy - r, r * 2, r * 2); + } + } + function gradient(defs, str) { + var grad = eve("snap.util.grad.parse", null, str).firstDefined(), + el; + if (!grad) { + return null; + } + grad.params.unshift(defs); + if (grad.type.toLowerCase() == "l") { + el = gradientLinear.apply(0, grad.params); + } else { + el = gradientRadial.apply(0, grad.params); + } + if (grad.type != grad.type.toLowerCase()) { + $(el.node, { + gradientUnits: "userSpaceOnUse" + }); + } + var stops = grad.stops, + len = stops.length, + start = 0, + j = 0; + function seed(i, end) { + var step = (end - start) / (i - j); + for (var k = j; k < i; k++) { + stops[k].offset = +(+start + step * (k - j)).toFixed(2); + } + j = i; + start = end; + } + len--; + for (var i = 0; i < len; i++) if ("offset" in stops[i]) { + seed(i, stops[i].offset); + } + stops[len].offset = stops[len].offset || 100; + seed(len, stops[len].offset); + for (i = 0; i <= len; i++) { + var stop = stops[i]; + el.addStop(stop.color, stop.offset); + } + return el; + } + function gradientLinear(defs, x1, y1, x2, y2) { + var el = Snap._.make("linearGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (x1 != null) { + $(el.node, { + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }); + } + return el; + } + function gradientRadial(defs, cx, cy, r, fx, fy) { + var el = Snap._.make("radialGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (cx != null) { + $(el.node, { + cx: cx, + cy: cy, + r: r + }); + } + if (fx != null && fy != null) { + $(el.node, { + fx: fx, + fy: fy + }); + } + return el; + } + /*\ + * Paper.gradient + [ method ] + ** + * Creates a gradient element + ** + - gradient (string) gradient descriptor + > Gradient Descriptor + * The gradient descriptor is an expression formatted as + * follows: `<type>(<coords>)<colors>`. The `<type>` can be + * either linear or radial. The uppercase `L` or `R` letters + * indicate absolute coordinates offset from the SVG surface. + * Lowercase `l` or `r` letters indicate coordinates + * calculated relative to the element to which the gradient is + * applied. Coordinates specify a linear gradient vector as + * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`, + * `r` and optional `fx`, `fy` specifying a focal point away + * from the center of the circle. Specify `<colors>` as a list + * of dash-separated CSS color values. Each color may be + * followed by a custom offset value, separated with a colon + * character. + > Examples + * Linear gradient, relative from top-left corner to bottom-right + * corner, from black through red to white: + | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff"); + * Linear gradient, absolute from (0, 0) to (100, 100), from black + * through red at 25% to white: + | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff"); + * Radial gradient, relative from the center of the element with radius + * half the width, from black to white: + | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff"); + * To apply the gradient: + | paper.circle(50, 50, 40).attr({ + | fill: g + | }); + = (object) the `gradient` element + \*/ + proto.gradient = function (str) { + return gradient(this.defs, str); + }; + proto.gradientLinear = function (x1, y1, x2, y2) { + return gradientLinear(this.defs, x1, y1, x2, y2); + }; + proto.gradientRadial = function (cx, cy, r, fx, fy) { + return gradientRadial(this.defs, cx, cy, r, fx, fy); + }; + /*\ + * Paper.toString + [ method ] + ** + * Returns SVG code for the @Paper + = (string) SVG code for the @Paper + \*/ + proto.toString = function () { + var doc = this.node.ownerDocument, + f = doc.createDocumentFragment(), + d = doc.createElement("div"), + svg = this.node.cloneNode(true), + res; + f.appendChild(d); + d.appendChild(svg); + Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"}); + res = d.innerHTML; + f.removeChild(f.firstChild); + return res; + }; + /*\ + * Paper.toDataURL + [ method ] + ** + * Returns SVG code for the @Paper as Data URI string. + = (string) Data URI string + \*/ + proto.toDataURL = function () { + if (window && window.btoa) { + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this))); + } + }; + /*\ + * Paper.clear + [ method ] + ** + * Removes all child nodes of the paper, except <defs>. + \*/ + proto.clear = function () { + var node = this.node.firstChild, + next; + while (node) { + next = node.nextSibling; + if (node.tagName != "defs") { + node.parentNode.removeChild(node); + } else { + proto.clear.call({node: node}); + } + node = next; + } + }; + }()); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + is = Snap.is, + clone = Snap._.clone, + has = "hasOwnProperty", + p2s = /,?([a-z]),?/gi, + toFloat = parseFloat, + math = Math, + PI = math.PI, + mmin = math.min, + mmax = math.max, + pow = math.pow, + abs = math.abs; + function paths(ps) { + var p = paths.ps = paths.ps || {}; + if (p[ps]) { + p[ps].sleep = 100; + } else { + p[ps] = { + sleep: 100 + }; + } + setTimeout(function () { + for (var key in p) if (p[has](key) && key != ps) { + p[key].sleep--; + !p[key].sleep && delete p[key]; + } + }); + return p[ps]; + } + function box(x, y, width, height) { + if (x == null) { + x = y = width = height = 0; + } + if (y == null) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + return { + x: x, + y: y, + width: width, + w: width, + height: height, + h: height, + x2: x + width, + y2: y + height, + cx: x + width / 2, + cy: y + height / 2, + r1: math.min(width, height) / 2, + r2: math.max(width, height) / 2, + r0: math.sqrt(width * width + height * height) / 2, + path: rectPath(x, y, width, height), + vb: [x, y, width, height].join(" ") + }; + } + function toString() { + return this.join(",").replace(p2s, "$1"); + } + function pathClone(pathArray) { + var res = clone(pathArray); + res.toString = toString; + return res; + } + function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + if (length == null) { + return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + } else { + return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, + getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); + } + } + function getLengthFactory(istotal, subpath) { + function O(val) { + return +(+val).toFixed(3); + } + return Snap._.cacher(function (path, length, onlystart) { + if (path instanceof Element) { + path = path.attr("d"); + } + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += [ + "C" + O(point.start.x), + O(point.start.y), + O(point.m.x), + O(point.m.y), + O(point.x), + O(point.y) + ]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = [ + "M" + O(point.x), + O(point.y) + "C" + O(point.n.x), + O(point.n.y), + O(point.end.x), + O(point.end.y), + O(p[5]), + O(p[6]) + ].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return point; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + return point; + }, null, Snap._.clone); + } + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + // (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + } + function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + if (!Snap.is(p1x, "array")) { + p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; + } + var bbox = curveDim.apply(null, p1x); + return box( + bbox.min.x, + bbox.min.y, + bbox.max.x - bbox.min.x, + bbox.max.y - bbox.min.y + ); + } + function isPointInsideBBox(bbox, x, y) { + return x >= bbox.x && + x <= bbox.x + bbox.width && + y >= bbox.y && + y <= bbox.y + bbox.height; + } + function isBBoxIntersect(bbox1, bbox2) { + bbox1 = box(bbox1); + bbox2 = box(bbox2); + return isPointInsideBBox(bbox2, bbox1.x, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2) + || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x + || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) + && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y + || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); + } + function base3(t, p1, p2, p3, p4) { + var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, + t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; + return t * t2 - 3 * p1 + 3 * p2; + } + function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { + if (z == null) { + z = 1; + } + z = z > 1 ? 1 : z < 0 ? 0 : z; + var z2 = z / 2, + n = 12, + Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816], + Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], + sum = 0; + for (var i = 0; i < n; i++) { + var ct = z2 * Tvalues[i] + z2, + xbase = base3(ct, x1, x2, x3, x4), + ybase = base3(ct, y1, y2, y3, y4), + comb = xbase * xbase + ybase * ybase; + sum += Cvalues[i] * math.sqrt(comb); + } + return z2 * sum; + } + function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { + if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { + return; + } + var t = 1, + step = t / 2, + t2 = t - step, + l, + e = .01; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + while (abs(l - ll) > e) { + step /= 2; + t2 += (l < ll ? 1 : -1) * step; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + } + return t2; + } + function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { + if ( + mmax(x1, x2) < mmin(x3, x4) || + mmin(x1, x2) > mmax(x3, x4) || + mmax(y1, y2) < mmin(y3, y4) || + mmin(y1, y2) > mmax(y3, y4) + ) { + return; + } + var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), + ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), + denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + + if (!denominator) { + return; + } + var px = nx / denominator, + py = ny / denominator, + px2 = +px.toFixed(2), + py2 = +py.toFixed(2); + if ( + px2 < +mmin(x1, x2).toFixed(2) || + px2 > +mmax(x1, x2).toFixed(2) || + px2 < +mmin(x3, x4).toFixed(2) || + px2 > +mmax(x3, x4).toFixed(2) || + py2 < +mmin(y1, y2).toFixed(2) || + py2 > +mmax(y1, y2).toFixed(2) || + py2 < +mmin(y3, y4).toFixed(2) || + py2 > +mmax(y3, y4).toFixed(2) + ) { + return; + } + return {x: px, y: py}; + } + function inter(bez1, bez2) { + return interHelper(bez1, bez2); + } + function interCount(bez1, bez2) { + return interHelper(bez1, bez2, 1); + } + function interHelper(bez1, bez2, justCount) { + var bbox1 = bezierBBox(bez1), + bbox2 = bezierBBox(bez2); + if (!isBBoxIntersect(bbox1, bbox2)) { + return justCount ? 0 : []; + } + var l1 = bezlen.apply(0, bez1), + l2 = bezlen.apply(0, bez2), + n1 = ~~(l1 / 8), + n2 = ~~(l2 / 8), + dots1 = [], + dots2 = [], + xy = {}, + res = justCount ? 0 : []; + for (var i = 0; i < n1 + 1; i++) { + var p = findDotsAtSegment.apply(0, bez1.concat(i / n1)); + dots1.push({x: p.x, y: p.y, t: i / n1}); + } + for (i = 0; i < n2 + 1; i++) { + p = findDotsAtSegment.apply(0, bez2.concat(i / n2)); + dots2.push({x: p.x, y: p.y, t: i / n2}); + } + for (i = 0; i < n1; i++) { + for (var j = 0; j < n2; j++) { + var di = dots1[i], + di1 = dots1[i + 1], + dj = dots2[j], + dj1 = dots2[j + 1], + ci = abs(di1.x - di.x) < .001 ? "y" : "x", + cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", + is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); + if (is) { + if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { + continue; + } + xy[is.x.toFixed(4)] = is.y.toFixed(4); + var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), + t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); + if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) { + if (justCount) { + res++; + } else { + res.push({ + x: is.x, + y: is.y, + t1: t1, + t2: t2 + }); + } + } + } + } + } + return res; + } + function pathIntersection(path1, path2) { + return interPathHelper(path1, path2); + } + function pathIntersectionNumber(path1, path2) { + return interPathHelper(path1, path2, 1); + } + function interPathHelper(path1, path2, justCount) { + path1 = path2curve(path1); + path2 = path2curve(path2); + var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, + res = justCount ? 0 : []; + for (var i = 0, ii = path1.length; i < ii; i++) { + var pi = path1[i]; + if (pi[0] == "M") { + x1 = x1m = pi[1]; + y1 = y1m = pi[2]; + } else { + if (pi[0] == "C") { + bez1 = [x1, y1].concat(pi.slice(1)); + x1 = bez1[6]; + y1 = bez1[7]; + } else { + bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; + x1 = x1m; + y1 = y1m; + } + for (var j = 0, jj = path2.length; j < jj; j++) { + var pj = path2[j]; + if (pj[0] == "M") { + x2 = x2m = pj[1]; + y2 = y2m = pj[2]; + } else { + if (pj[0] == "C") { + bez2 = [x2, y2].concat(pj.slice(1)); + x2 = bez2[6]; + y2 = bez2[7]; + } else { + bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; + x2 = x2m; + y2 = y2m; + } + var intr = interHelper(bez1, bez2, justCount); + if (justCount) { + res += intr; + } else { + for (var k = 0, kk = intr.length; k < kk; k++) { + intr[k].segment1 = i; + intr[k].segment2 = j; + intr[k].bez1 = bez1; + intr[k].bez2 = bez2; + } + res = res.concat(intr); + } + } + } + } + } + return res; + } + function isPointInsidePath(path, x, y) { + var bbox = pathBBox(path); + return isPointInsideBBox(bbox, x, y) && + interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; + } + function pathBBox(path) { + var pth = paths(path); + if (pth.bbox) { + return clone(pth.bbox); + } + if (!path) { + return box(); + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X.concat(dim.min.x, dim.max.x); + Y = Y.concat(dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin.apply(0, X), + ymin = mmin.apply(0, Y), + xmax = mmax.apply(0, X), + ymax = mmax.apply(0, Y), + bb = box(xmin, ymin, xmax - xmin, ymax - ymin); + pth.bbox = clone(bb); + return bb; + } + function rectPath(x, y, w, h, r) { + if (r) { + return [ + ["M", +x + (+r), y], + ["l", w - r * 2, 0], + ["a", r, r, 0, 0, 1, r, r], + ["l", 0, h - r * 2], + ["a", r, r, 0, 0, 1, -r, r], + ["l", r * 2 - w, 0], + ["a", r, r, 0, 0, 1, -r, -r], + ["l", 0, r * 2 - h], + ["a", r, r, 0, 0, 1, r, -r], + ["z"] + ]; + } + var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + res.toString = toString; + return res; + } + function ellipsePath(x, y, rx, ry, a) { + if (a == null && ry == null) { + ry = rx; + } + x = +x; + y = +y; + rx = +rx; + ry = +ry; + if (a != null) { + var rad = Math.PI / 180, + x1 = x + rx * Math.cos(-ry * rad), + x2 = x + rx * Math.cos(-a * rad), + y1 = y + rx * Math.sin(-ry * rad), + y2 = y + rx * Math.sin(-a * rad), + res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]]; + } else { + res = [ + ["M", x, y], + ["m", 0, -ry], + ["a", rx, ry, 0, 1, 1, 0, 2 * ry], + ["a", rx, ry, 0, 1, 1, 0, -2 * ry], + ["z"] + ]; + } + res.toString = toString; + return res; + } + var unit2px = Snap._unit2px, + getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx, attr.cy, attr.r); + }, + ellipse: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry); + }, + rect: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry); + }, + image: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height); + }, + line: function (el) { + return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")]; + }, + polyline: function (el) { + return "M" + el.attr("points"); + }, + polygon: function (el) { + return "M" + el.attr("points") + "z"; + }, + deflt: function (el) { + var bbox = el.node.getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }; + function pathToRelative(pathArray) { + var pth = paths(pathArray), + lowerCase = String.prototype.toLowerCase; + if (pth.rel) { + return pathClone(pth.rel); + } + if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) { + pathArray = Snap.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = toString; + pth.rel = pathClone(res); + return res; + } + function pathToAbsolute(pathArray) { + var pth = paths(pathArray); + if (pth.abs) { + return pathClone(pth.abs); + } + if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption + pathArray = Snap.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0, + pa0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + var crz = pathArray.length == 3 && + pathArray[0][0] == "M" && + pathArray[1][0].toUpperCase() == "R" && + pathArray[2][0].toUpperCase() == "Z"; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + pa0 = pa[0]; + if (pa0 != pa0.toUpperCase()) { + r[0] = pa0.toUpperCase(); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +pa[6] + x; + r[7] = +pa[7] + y; + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y].concat(pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + break; + case "O": + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + break; + case "U": + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa0 == "R") { + dots = [x, y].concat(pa.slice(1)); + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + r = ["R"].concat(pa.slice(-2)); + } else if (pa0 == "O") { + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + } else if (pa0 == "U") { + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + pa0 = pa0.toUpperCase(); + if (pa0 != "O") { + switch (r[0]) { + case "Z": + x = +mx; + y = +my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + } + res.toString = toString; + pth.abs = pathClone(res); + return res; + } + function l2c(x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + } + function q2c(x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + } + function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = Snap._.cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4].concat(res); + } else { + res = [m2, m3, m4].concat(res).join().split(","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + } + function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + } + + // Returns bounding box of cubic bezier curve. + // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + // Original version: NISHIO Hirokazu + // Modifications: https://github.com/timo22345 + function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) { + var tvalues = [], + bounds = [[], []], + a, b, c, t, t1, t2, b2ac, sqrtb2ac; + for (var i = 0; i < 2; ++i) { + if (i == 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + if (abs(a) < 1e-12) { + if (abs(b) < 1e-12) { + continue; + } + t = -c / b; + if (0 < t && t < 1) { + tvalues.push(t); + } + continue; + } + b2ac = b * b - 4 * c * a; + sqrtb2ac = math.sqrt(b2ac); + if (b2ac < 0) { + continue; + } + t1 = (-b + sqrtb2ac) / (2 * a); + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + t2 = (-b - sqrtb2ac) / (2 * a); + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + var x, y, j = tvalues.length, + jlen = j, + mt; + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); + bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + + + return { + min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])}, + max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])} + }; + } + + function path2curve(path, path2) { + var pth = !path2 && paths(path); + if (!path2 && pth.curve) { + return pathClone(pth.curve); + } + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d, pcom) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); + break; + case "S": + if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. + nx = d.x * 2 - d.bx; // And reflect the previous + ny = d.y * 2 - d.by; // command's control point relative to the current point. + } + else { // or some else or nothing + nx = d.x; + ny = d.y; + } + path = ["C", nx, ny].concat(path.slice(1)); + break; + case "T": + if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. + d.qx = d.x * 2 - d.qx; // And make a reflection similar + d.qy = d.y * 2 - d.qy; // to case "S". + } + else { // or something else or nothing + d.qx = d.x; + d.qy = d.y; + } + path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"].concat(l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"].concat(l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"].concat(l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved + p2 && (pcoms2[i] = "A"); // the same as above + pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + pcoms1 = [], // path commands of original path p + pcoms2 = [], // path commands of original path p2 + pfirst = "", // temporary holder for original path command + pcom = ""; // holder for previous path command of original path + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] && (pfirst = p[i][0]); // save current path command + + if (pfirst != "C") // C is not saved yet, because it may be result of conversion + { + pcoms1[i] = pfirst; // Save current path command + i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom + } + p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath + + if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command + // which may produce multiple C:s + // so we have to make sure that C is also C in original path + + fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 + + if (p2) { // the same procedures is done to p2 + p2[i] && (pfirst = p2[i][0]); + if (pfirst != "C") { + pcoms2[i] = pfirst; + i && (pcom = pcoms2[i - 1]); + } + p2[i] = processPath(p2[i], attrs2, pcom); + + if (pcoms2[i] != "A" && pfirst == "C") { + pcoms2[i] = "C"; + } + + fixArc(p2, i); + } + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + if (!p2) { + pth.curve = pathClone(p); + } + return p2 ? [p, p2] : p; + } + function mapPath(path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + } + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 == i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 == i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 == i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + // export + Snap.path = paths; + + /*\ + * Snap.path.getTotalLength + [ method ] + ** + * Returns the length of the given path in pixels + ** + - path (string) SVG path string + ** + = (number) length + \*/ + Snap.path.getTotalLength = getTotalLength; + /*\ + * Snap.path.getPointAtLength + [ method ] + ** + * Returns the coordinates of the point located at the given length along the given path + ** + - path (string) SVG path string + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + Snap.path.getPointAtLength = getPointAtLength; + /*\ + * Snap.path.getSubpath + [ method ] + ** + * Returns the subpath of a given path between given start and end lengths + ** + - path (string) SVG path string + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + Snap.path.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + /*\ + * Element.getTotalLength + [ method ] + ** + * Returns the length of the path in pixels (only works for `path` elements) + = (number) length + \*/ + elproto.getTotalLength = function () { + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + }; + // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length? + /*\ + * Element.getPointAtLength + [ method ] + ** + * Returns coordinates of the point located at the given length on the given path (only works for `path` elements) + ** + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + elproto.getPointAtLength = function (length) { + return getPointAtLength(this.attr("d"), length); + }; + // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear. + /*\ + * Element.getSubpath + [ method ] + ** + * Returns subpath of a given element from given start and end lengths (only works for `path` elements) + ** + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + elproto.getSubpath = function (from, to) { + return Snap.path.getSubpath(this.attr("d"), from, to); + }; + Snap._.box = box; + /*\ + * Snap.path.findDotsAtSegment + [ method ] + ** + * Utility method + ** + * Finds dot coordinates on the given cubic beziér curve at the given t + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + - t (number) position on the curve (0..1) + = (object) point information in format: + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o m: { + o x: (number) x coordinate of the left anchor, + o y: (number) y coordinate of the left anchor + o }, + o n: { + o x: (number) x coordinate of the right anchor, + o y: (number) y coordinate of the right anchor + o }, + o start: { + o x: (number) x coordinate of the start of the curve, + o y: (number) y coordinate of the start of the curve + o }, + o end: { + o x: (number) x coordinate of the end of the curve, + o y: (number) y coordinate of the end of the curve + o }, + o alpha: (number) angle of the curve derivative at the point + o } + \*/ + Snap.path.findDotsAtSegment = findDotsAtSegment; + /*\ + * Snap.path.bezierBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given cubic beziér curve + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + * or + - bez (array) array of six points for beziér curve + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.bezierBBox = bezierBBox; + /*\ + * Snap.path.isPointInsideBBox + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside bounding box + - bbox (string) bounding box + - x (string) x coordinate of the point + - y (string) y coordinate of the point + = (boolean) `true` if point is inside + \*/ + Snap.path.isPointInsideBBox = isPointInsideBBox; + Snap.closest = function (x, y, X, Y) { + var r = 100, + b = box(x - r / 2, y - r / 2, r, r), + inside = [], + getter = X[0].hasOwnProperty("x") ? function (i) { + return { + x: X[i].x, + y: X[i].y + }; + } : function (i) { + return { + x: X[i], + y: Y[i] + }; + }, + found = 0; + while (r <= 1e6 && !found) { + for (var i = 0, ii = X.length; i < ii; i++) { + var xy = getter(i); + if (isPointInsideBBox(b, xy.x, xy.y)) { + found++; + inside.push(xy); + break; + } + } + if (!found) { + r *= 2; + b = box(x - r / 2, y - r / 2, r, r) + } + } + if (r == 1e6) { + return; + } + var len = Infinity, + res; + for (i = 0, ii = inside.length; i < ii; i++) { + var l = Snap.len(x, y, inside[i].x, inside[i].y); + if (len > l) { + len = l; + inside[i].len = l; + res = inside[i]; + } + } + return res; + }; + /*\ + * Snap.path.isBBoxIntersect + [ method ] + ** + * Utility method + ** + * Returns `true` if two bounding boxes intersect + - bbox1 (string) first bounding box + - bbox2 (string) second bounding box + = (boolean) `true` if bounding boxes intersect + \*/ + Snap.path.isBBoxIntersect = isBBoxIntersect; + /*\ + * Snap.path.intersection + [ method ] + ** + * Utility method + ** + * Finds intersections of two paths + - path1 (string) path string + - path2 (string) path string + = (array) dots of intersection + o [ + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o t1: (number) t value for segment of path1, + o t2: (number) t value for segment of path2, + o segment1: (number) order number for segment of path1, + o segment2: (number) order number for segment of path2, + o bez1: (array) eight coordinates representing beziér curve for the segment of path1, + o bez2: (array) eight coordinates representing beziér curve for the segment of path2 + o } + o ] + \*/ + Snap.path.intersection = pathIntersection; + Snap.path.intersectionNumber = pathIntersectionNumber; + /*\ + * Snap.path.isPointInside + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside a given closed path. + * + * Note: fill mode doesn’t affect the result of this method. + - path (string) path string + - x (number) x of the point + - y (number) y of the point + = (boolean) `true` if point is inside the path + \*/ + Snap.path.isPointInside = isPointInsidePath; + /*\ + * Snap.path.getBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given path + - path (string) path string + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.getBBox = pathBBox; + Snap.path.get = getPath; + /*\ + * Snap.path.toRelative + [ method ] + ** + * Utility method + ** + * Converts path coordinates into relative values + - path (string) path string + = (array) path string + \*/ + Snap.path.toRelative = pathToRelative; + /*\ + * Snap.path.toAbsolute + [ method ] + ** + * Utility method + ** + * Converts path coordinates into absolute values + - path (string) path string + = (array) path string + \*/ + Snap.path.toAbsolute = pathToAbsolute; + /*\ + * Snap.path.toCubic + [ method ] + ** + * Utility method + ** + * Converts path to a new path where all segments are cubic beziér curves + - pathString (string|array) path string or array of segments + = (array) array of segments + \*/ + Snap.path.toCubic = path2curve; + /*\ + * Snap.path.map + [ method ] + ** + * Transform the path string with the given matrix + - path (string) path string + - matrix (object) see @Matrix + = (string) transformed path string + \*/ + Snap.path.map = mapPath; + Snap.path.toString = toString; + Snap.path.clone = pathClone; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var mmax = Math.max, + mmin = Math.min; + + // Set + var Set = function (items) { + this.items = []; + this.bindings = {}; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i]) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + /*\ + * Set.push + [ method ] + ** + * Adds each argument to the current set + = (object) original element + \*/ + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + /*\ + * Set.pop + [ method ] + ** + * Removes last element and returns it + = (object) element + \*/ + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + /*\ + * Set.forEach + [ method ] + ** + * Executes given function for each element in the set + * + * If the function returns `false`, the loop stops running. + ** + - callback (function) function to run + - thisArg (object) context object for the callback + = (object) Set object + \*/ + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + /*\ + * Set.animate + [ method ] + ** + * Animates each element in set in sync. + * + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + * or + - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]` + > Usage + | // animate all elements in set to radius 10 + | set.animate({r: 10}, 500, mina.easein); + | // or + | // animate first element to radius 10, but second to radius 20 and in different time + | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]); + = (Element) the current element + \*/ + setproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Snap._.Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = easing.dur; + attrs = attrs.attr; + } + var args = arguments; + if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) { + var each = true; + } + var begin, + handler = function () { + if (begin) { + this.b = begin; + } else { + begin = this.b; + } + }, + cb = 0, + set = this, + callbacker = callback && function () { + if (++cb == set.length) { + callback.call(this); + } + }; + return this.forEach(function (el, i) { + eve.once("snap.animcreated." + el.id, handler); + if (each) { + args[i] && el.animate.apply(el, args[i]); + } else { + el.animate(attrs, ms, easing, callbacker); + } + }); + }; + setproto.remove = function () { + while (this.length) { + this.pop().remove(); + } + return this; + }; + /*\ + * Set.bind + [ method ] + ** + * Specifies how to handle a specific attribute when applied + * to a set. + * + ** + - attr (string) attribute name + - callback (function) function to run + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + - eattr (string) attribute on the element to bind the attribute to + = (object) Set object + \*/ + setproto.bind = function (attr, a, b) { + var data = {}; + if (typeof a == "function") { + this.bindings[attr] = a; + } else { + var aname = b || attr; + this.bindings[attr] = function (v) { + data[aname] = v; + a.attr(data); + }; + } + return this; + }; + setproto.attr = function (value) { + var unbound = {}; + for (var k in value) { + if (this.bindings[k]) { + this.bindings[k](value[k]); + } else { + unbound[k] = value[k]; + } + } + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(unbound); + } + return this; + }; + /*\ + * Set.clear + [ method ] + ** + * Removes all elements from the set + \*/ + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + /*\ + * Set.splice + [ method ] + ** + * Removes range of elements from the set + ** + - index (number) position of the deletion + - count (number) number of element to remove + - insertion… (object) #optional elements to insert + = (object) set elements that were deleted + \*/ + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + /*\ + * Set.exclude + [ method ] + ** + * Removes given element from the set + ** + - element (object) element to remove + = (boolean) `true` if object was found and removed from the set + \*/ + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + return false; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + x2 = [], + y2 = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + x2.push(box.x + box.width); + y2.push(box.y + box.height); + } + x = mmin.apply(0, x); + y = mmin.apply(0, y); + x2 = mmax.apply(0, x2); + y2 = mmax.apply(0, y2); + return { + x: x, + y: y, + x2: x2, + y2: y2, + width: x2 - x, + height: y2 - y, + cx: x + (x2 - x) / 2, + cy: y + (y2 - y) / 2 + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Snap\u2018s set"; + }; + setproto.type = "set"; + // export + Snap.Set = Set; + Snap.set = function () { + var set = new Set; + if (arguments.length) { + set.push.apply(set, Array.prototype.slice.call(arguments, 0)); + } + return set; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var names = {}, + reUnit = /[a-z]+$/i, + Str = String; + names.stroke = names.fill = "colour"; + function getEmpty(item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + } + function equaliseTransform(t1, t2, getBBox) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = Snap.parseTransformString(t1) || []; + t2 = Snap.parseTransformString(t2) || []; + var maxlength = Math.max(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + t1 = Snap._.transform2matrix(t1, getBBox()); + t2 = Snap._.transform2matrix(t2, getBBox()); + from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]]; + to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]]; + break; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: path2array(from), + to: path2array(to), + f: getPath(from) + }; + } + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + function getViewBox(val) { + return val.join(" "); + } + function getColour(clr) { + return Snap.rgb(clr[0], clr[1], clr[2]); + } + function getPath(path) { + var k = 0, i, ii, j, jj, out, a, b = []; + for (i = 0, ii = path.length; i < ii; i++) { + out = "["; + a = ['"' + path[i][0] + '"']; + for (j = 1, jj = path[i].length; j < jj; j++) { + a[j] = "val[" + (k++) + "]"; + } + out += a + "]"; + b[i] = out; + } + return Function("val", "return Snap.path.toString.call([" + b + "])"); + } + function path2array(path) { + var out = []; + for (var i = 0, ii = path.length; i < ii; i++) { + for (var j = 1, jj = path[i].length; j < jj; j++) { + out.push(path[i][j]); + } + } + return out; + } + function isNumeric(obj) { + return isFinite(parseFloat(obj)); + } + function arrayEqual(arr1, arr2) { + if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) { + return false; + } + return arr1.toString() == arr2.toString(); + } + Element.prototype.equal = function (name, b) { + return eve("snap.util.equal", this, name, b).firstDefined(); + }; + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this; + if (isNumeric(a) && isNumeric(b)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getNumber + }; + } + if (names[name] == "colour") { + A = Snap.color(a); + B = Snap.color(b); + return { + from: [A.r, A.g, A.b, A.opacity], + to: [B.r, B.g, B.b, B.opacity], + f: getColour + }; + } + if (name == "viewBox") { + A = this.attr(name).vb.split(" ").map(Number); + B = b.split(" ").map(Number); + return { + from: A, + to: B, + f: getViewBox + }; + } + if (name == "transform" || name == "gradientTransform" || name == "patternTransform") { + if (b instanceof Snap.Matrix) { + b = b.toTransformString(); + } + if (!Snap._.rgTransform.test(b)) { + b = Snap._.svgTransform2string(b); + } + return equaliseTransform(a, b, function () { + return el.getBBox(1); + }); + } + if (name == "d" || name == "path") { + A = Snap.path.toCubic(a, b); + return { + from: path2array(A[0]), + to: path2array(A[1]), + f: getPath(A[0]) + }; + } + if (name == "points") { + A = Str(a).split(Snap._.separator); + B = Str(b).split(Snap._.separator); + return { + from: A, + to: B, + f: function (val) { return val; } + }; + } + var aUnit = a.match(reUnit), + bUnit = Str(b).match(reUnit); + if (aUnit && arrayEqual(aUnit, bUnit)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getUnit(aUnit) + }; + } else { + return { + from: this.asPX(name), + to: this.asPX(name, b), + f: getNumber + }; + } + }); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + has = "hasOwnProperty", + supportsTouch = "createTouch" in glob.doc, + events = [ + "click", "dblclick", "mousedown", "mousemove", "mouseout", + "mouseover", "mouseup", "touchstart", "touchmove", "touchend", + "touchcancel" + ], + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + getScroll = function (xy, el) { + var name = xy == "y" ? "scrollTop" : "scrollLeft", + doc = el && el.node ? el.node.ownerDocument : glob.doc; + return doc[name in doc.documentElement ? "documentElement" : "body"][name]; + }, + preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = getScroll("y", element), + scrollX = getScroll("x", element); + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + var x = e.clientX + scrollX, + y = e.clientY + scrollY; + return fn.call(element, e, x, y); + }; + + if (type !== realName) { + obj.addEventListener(type, f, false); + } + + obj.addEventListener(realName, f, false); + + return function () { + if (type !== realName) { + obj.removeEventListener(type, f, false); + } + + obj.removeEventListener(realName, f, false); + return true; + }; + }, + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = getScroll("y"), + scrollX = getScroll("x"), + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches && e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + // glob.win.opera && parent.removeChild(node); + // node.style.display = "none"; + // o = dragi.el.paper.getElementByPoint(x, y); + // node.style.display = display; + // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + Snap.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + eve.off("snap.drag.*." + dragi.el.id); + } + drag = []; + }; + /*\ + * Element.click + [ method ] + ** + * Adds a click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unclick + [ method ] + ** + * Removes a click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.dblclick + [ method ] + ** + * Adds a double click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.undblclick + [ method ] + ** + * Removes a double click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousedown + [ method ] + ** + * Adds a mousedown event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousedown + [ method ] + ** + * Removes a mousedown event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousemove + [ method ] + ** + * Adds a mousemove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousemove + [ method ] + ** + * Removes a mousemove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseout + [ method ] + ** + * Adds a mouseout event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseout + [ method ] + ** + * Removes a mouseout event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseover + [ method ] + ** + * Adds a mouseover event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseover + [ method ] + ** + * Removes a mouseover event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseup + [ method ] + ** + * Adds a mouseup event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseup + [ method ] + ** + * Removes a mouseup event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchstart + [ method ] + ** + * Adds a touchstart event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchstart + [ method ] + ** + * Removes a touchstart event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchmove + [ method ] + ** + * Adds a touchmove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchmove + [ method ] + ** + * Removes a touchmove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchend + [ method ] + ** + * Adds a touchend event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchend + [ method ] + ** + * Removes a touchend event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchcancel + [ method ] + ** + * Adds a touchcancel event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchcancel + [ method ] + ** + * Removes a touchcancel event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + for (var i = events.length; i--;) { + (function (eventName) { + Snap[eventName] = elproto[eventName] = function (fn, scope) { + if (Snap.is(fn, "function")) { + this.events = this.events || []; + this.events.push({ + name: eventName, + f: fn, + unbind: addEvent(this.node || document, eventName, fn, scope || this) + }); + } else { + for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) { + try { + this.events[i].f.call(this); + } catch (e) {} + } + } + return this; + }; + Snap["un" + eventName] = + elproto["un" + eventName] = function (fn) { + var events = this.events || [], + l = events.length; + while (l--) if (events[l].name == eventName && + (events[l].f == fn || !fn)) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + /*\ + * Element.hover + [ method ] + ** + * Adds hover event handlers to the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + - icontext (object) #optional context for hover in handler + - ocontext (object) #optional context for hover out handler + = (object) @Element + \*/ + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + /*\ + * Element.unhover + [ method ] + ** + * Removes hover event handlers from the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + = (object) @Element + \*/ + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture. + // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from? + // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason. + // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID? + /*\ + * Element.drag + [ method ] + ** + * Adds event handlers for an element's drag gesture + ** + - onmove (function) handler for moving + - onstart (function) handler for drag start + - onend (function) handler for drag end + - mcontext (object) #optional context for moving handler + - scontext (object) #optional context for drag start handler + - econtext (object) #optional context for drag end handler + * Additionaly following `drag` events are triggered: `drag.start.<id>` on start, + * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element + * `drag.over.<id>` fires as well. + * + * Start event and start handler are called in specified context or in context of the element with following parameters: + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * Move event and move handler are called in specified context or in context of the element with following parameters: + o dx (number) shift by x from the start point + o dy (number) shift by y from the start point + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * End event and end handler are called in specified context or in context of the element with following parameters: + o event (object) DOM event object + = (object) @Element + \*/ + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + var el = this; + if (!arguments.length) { + var origTransform; + return el.drag(function (dx, dy) { + this.attr({ + transform: origTransform + (origTransform ? "T" : "t") + [dx, dy] + }); + }, function () { + origTransform = this.transform().local; + }); + } + function start(e, x, y) { + (e.originalEvent || e).preventDefault(); + el._drag.x = x; + el._drag.y = y; + el._drag.id = e.identifier; + !drag.length && Snap.mousemove(dragMove).mouseup(dragUp); + drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("snap.drag.start." + el.id, onstart); + onmove && eve.on("snap.drag.move." + el.id, onmove); + onend && eve.on("snap.drag.end." + el.id, onend); + eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e); + } + function init(e, x, y) { + eve("snap.draginit." + el.id, el, e, x, y); + } + eve.on("snap.draginit." + el.id, start); + el._drag = {}; + draggable.push({el: el, start: start, init: init}); + el.mousedown(init); + return el; + }; + /* + * Element.onDragOver + [ method ] + ** + * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id) + - f (function) handler for event, first argument would be the element you are dragging over + \*/ + // elproto.onDragOver = function (f) { + // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id); + // }; + /*\ + * Element.undrag + [ method ] + ** + * Removes all drag event handlers from the given element + \*/ + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].init); + draggable.splice(i, 1); + eve.unbind("snap.drag.*." + this.id); + eve.unbind("snap.draginit." + this.id); + } + !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp); + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + pproto = Paper.prototype, + rgurl = /^\s*url\((.+)\)/, + Str = String, + $ = Snap._.$; + Snap.filter = {}; + /*\ + * Paper.filter + [ method ] + ** + * Creates a `<filter>` element + ** + - filstr (string) SVG fragment of filter provided as a string + = (object) @Element + * Note: It is recommended to use filters embedded into the page inside an empty SVG element. + > Usage + | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + pproto.filter = function (filstr) { + var paper = this; + if (paper.type != "svg") { + paper = paper.paper; + } + var f = Snap.parse(Str(filstr)), + id = Snap._.id(), + width = paper.node.offsetWidth, + height = paper.node.offsetHeight, + filter = $("filter"); + $(filter, { + id: id, + filterUnits: "userSpaceOnUse" + }); + filter.appendChild(f.node); + paper.defs.appendChild(filter); + return new Element(filter); + }; + + eve.on("snap.util.getattr.filter", function () { + eve.stop(); + var p = $(this.node, "filter"); + if (p) { + var match = Str(p).match(rgurl); + return match && Snap.select(match[1]); + } + }); + eve.on("snap.util.attr.filter", function (value) { + if (value instanceof Element && value.type == "filter") { + eve.stop(); + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + id = value.id; + } + $(this.node, { + filter: Snap.url(id) + }); + } + if (!value || value == "none") { + eve.stop(); + this.node.removeAttribute("filter"); + } + }); + /*\ + * Snap.filter.blur + [ method ] + ** + * Returns an SVG markup string for the blur filter + ** + - x (number) amount of horizontal blur, in pixels + - y (number) #optional amount of vertical blur, in pixels + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.blur(5, 10)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.blur = function (x, y) { + if (x == null) { + x = 2; + } + var def = y == null ? x : [x, y]; + return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', { + def: def + }); + }; + Snap.filter.blur.toString = function () { + return this(); + }; + /*\ + * Snap.filter.shadow + [ method ] + ** + * Returns an SVG markup string for the shadow filter + ** + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - blur (number) #optional amount of blur + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * which makes blur default to `4`. Or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - opacity (number) #optional `0..1` opacity of the shadow + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.shadow(0, 2, 3)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.shadow = function (dx, dy, blur, color, opacity) { + if (typeof blur == "string") { + color = blur; + opacity = color; + blur = 4; + } + if (typeof color != "string") { + opacity = color; + color = "#000"; + } + color = color || "#000"; + if (blur == null) { + blur = 4; + } + if (opacity == null) { + opacity = 1; + } + if (dx == null) { + dx = 0; + dy = 2; + } + if (dy == null) { + dy = dx; + } + color = Snap.color(color); + return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', { + color: color, + dx: dx, + dy: dy, + blur: blur, + opacity: opacity + }); + }; + Snap.filter.shadow.toString = function () { + return this(); + }; + /*\ + * Snap.filter.grayscale + [ method ] + ** + * Returns an SVG markup string for the grayscale filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.grayscale = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', { + a: 0.2126 + 0.7874 * (1 - amount), + b: 0.7152 - 0.7152 * (1 - amount), + c: 0.0722 - 0.0722 * (1 - amount), + d: 0.2126 - 0.2126 * (1 - amount), + e: 0.7152 + 0.2848 * (1 - amount), + f: 0.0722 - 0.0722 * (1 - amount), + g: 0.2126 - 0.2126 * (1 - amount), + h: 0.0722 + 0.9278 * (1 - amount) + }); + }; + Snap.filter.grayscale.toString = function () { + return this(); + }; + /*\ + * Snap.filter.sepia + [ method ] + ** + * Returns an SVG markup string for the sepia filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.sepia = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', { + a: 0.393 + 0.607 * (1 - amount), + b: 0.769 - 0.769 * (1 - amount), + c: 0.189 - 0.189 * (1 - amount), + d: 0.349 - 0.349 * (1 - amount), + e: 0.686 + 0.314 * (1 - amount), + f: 0.168 - 0.168 * (1 - amount), + g: 0.272 - 0.272 * (1 - amount), + h: 0.534 - 0.534 * (1 - amount), + i: 0.131 + 0.869 * (1 - amount) + }); + }; + Snap.filter.sepia.toString = function () { + return this(); + }; + /*\ + * Snap.filter.saturate + [ method ] + ** + * Returns an SVG markup string for the saturate filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.saturate = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', { + amount: 1 - amount + }); + }; + Snap.filter.saturate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.hueRotate + [ method ] + ** + * Returns an SVG markup string for the hue-rotate filter + ** + - angle (number) angle of rotation + = (string) filter representation + \*/ + Snap.filter.hueRotate = function (angle) { + angle = angle || 0; + return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', { + angle: angle + }); + }; + Snap.filter.hueRotate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.invert + [ method ] + ** + * Returns an SVG markup string for the invert filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.invert = function (amount) { + if (amount == null) { + amount = 1; + } +// <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" color-interpolation-filters="sRGB"/> + return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: 1 - amount + }); + }; + Snap.filter.invert.toString = function () { + return this(); + }; + /*\ + * Snap.filter.brightness + [ method ] + ** + * Returns an SVG markup string for the brightness filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.brightness = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', { + amount: amount + }); + }; + Snap.filter.brightness.toString = function () { + return this(); + }; + /*\ + * Snap.filter.contrast + [ method ] + ** + * Returns an SVG markup string for the contrast filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.contrast = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: .5 - amount / 2 + }); + }; + Snap.filter.contrast.toString = function () { + return this(); + }; +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var box = Snap._.box, + is = Snap.is, + firstLetter = /^[^a-z]*([tbmlrc])/i, + toString = function () { + return "T" + this.dx + "," + this.dy; + }; + /*\ + * Element.getAlign + [ method ] + ** + * Returns shift needed to align the element relatively to given element. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string + > Usage + | el.transform(el.getAlign(el2, "top")); + * or + | var dy = el.getAlign(el2, "top").dy; + \*/ + Element.prototype.getAlign = function (el, way) { + if (way == null && is(el, "string")) { + way = el; + el = null; + } + el = el || this.paper; + var bx = el.getBBox ? el.getBBox() : box(el), + bb = this.getBBox(), + out = {}; + way = way && way.match(firstLetter); + way = way ? way[1].toLowerCase() : "c"; + switch (way) { + case "t": + out.dx = 0; + out.dy = bx.y - bb.y; + break; + case "b": + out.dx = 0; + out.dy = bx.y2 - bb.y2; + break; + case "m": + out.dx = 0; + out.dy = bx.cy - bb.cy; + break; + case "l": + out.dx = bx.x - bb.x; + out.dy = 0; + break; + case "r": + out.dx = bx.x2 - bb.x2; + out.dy = 0; + break; + default: + out.dx = bx.cx - bb.cx; + out.dy = 0; + break; + } + out.toString = toString; + return out; + }; + /*\ + * Element.align + [ method ] + ** + * Aligns the element relatively to given one via transformation. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object) this element + > Usage + | el.align(el2, "top"); + * or + | el.align("middle"); + \*/ + Element.prototype.align = function (el, way) { + return this.transform("..." + this.getAlign(el, way)); + }; +}); + +return Snap; +})); diff --git a/web/pgadmin/misc/templates/explain/js/explain.js b/web/pgadmin/misc/templates/explain/js/explain.js new file mode 100644 index 0000000..6efbdee --- /dev/null +++ b/web/pgadmin/misc/templates/explain/js/explain.js @@ -0,0 +1,688 @@ +define ( + 'pgadmin.misc.explain', + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'backbone', 'snap.svg'], + function($, _, S, pgAdmin, Backbone, Snap) { + +pgAdmin = pgAdmin || window.pgAdmin || {}; +var pgExplain = pgAdmin.Explain; + +// Snap.svg plug-in to write multitext as image name +Snap.plugin(function (Snap, Element, Paper, glob) { + Paper.prototype.multitext = function (x, y, txt, max_width, attributes) { + var svg = Snap(), + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + isWordBroken = false, + temp = svg.text(0, 0, abc); + + temp.attr(attributes); + + /* + * Find letter width in pixels and + * index from where the text should be broken + */ + var letter_width = temp.getBBox().width / abc.length, + word_break_index = Math.round((max_width / letter_width)) - 1; + + svg.remove(); + + var words = txt.split(" "), + width_so_far = 0, + lines=[], curr_line = '', + /* + * Function to divide string into multiple lines + * and store them in an array if it size crosses + * the max-width boundary. + */ + splitTextInMultiLine = function(leading, so_far, line) { + var l = line.length, + res = []; + + if (l == 0) + return res; + + if (so_far && (so_far + (l * letter_width) > max_width)) { + res.push(leading); + res = res.concat(splitTextInMultiLine('', 0, line)); + } else if (so_far) { + res.push(leading + ' ' + line); + } else { + if (leading) + res.push(leading); + if (line.length > word_break_index + 1) + res.push(line.slice(0, word_break_index) + '-'); + else + res.push(line); + res = res.concat(splitTextInMultiLine('', 0, line.slice(word_break_index))); + } + + return res; + }; + + for (var i = 0; i < words.length; i++) { + var tmpArr = splitTextInMultiLine( + curr_line, width_so_far, words[i] + ); + + if (curr_line) { + lines = lines.slice(0, lines.length - 2); + } + lines = lines.concat(tmpArr); + curr_line = lines[lines.length - 1]; + width_so_far = (curr_line.length * letter_width); + } + + // Create multiple tspan for each string in array + var t = this.text(x,y,lines).attr(attributes); + t.selectAll("tspan:nth-child(n+2)").attr({ + dy: "1.2em", + x: x + }); + return t; + }; +}); + +if (pgAdmin.Explain) + return pgAdmin.Explain; + +var pgExplain = pgAdmin.Explain = { + // Prefix path where images are stored + prefix: '{{ url_for('misc.static', filename='explain/img') }}/' +}; + +/* + * A map which is used to fetch the image to be drawn and + * text which will appear below it + */ +var imageMapper = { + "Aggregate" : { + "image":"ex_aggregate.png", "image_text":"Aggregate" + }, + 'Append' : { + "image":"ex_append.png","image_text":"Append" + }, + "Bitmap Index Scan" : function(data) { + return { + "image":"ex_bmp_index.png", "image_text":data['Index Name'] + }; + }, + "Bitmap Heap Scan" : function(data) { + return {"image":"ex_bmp_heap.png","image_text":data['Relation Name']}; +}, +"BitmapAnd" : {"image":"ex_bmp_and.png","image_text":"Bitmap AND"}, +"BitmapOr" : {"image":"ex_bmp_or.png","image_text":"Bitmap OR"}, +"CTE Scan" : {"image":"ex_cte_scan.png","image_text":"CTE Scan"}, +"Function Scan" : {"image":"ex_result.png","image_text":"Function Scan"}, +"Foreign Scan" : {"image":"ex_foreign_scan.png","image_text":"Foreign Scan"}, +"Gather" : {"image":"ex_gather_motion.png","image_text":"Gather"}, +"Group" : {"image":"ex_group.png","image_text":"Group"}, +"GroupAggregate": {"image":"ex_aggregate.png","image_text":"Group Aggregate"}, +"Hash" : {"image":"ex_hash.png","image_text":"Hash"}, +"Hash Join": function(data) { + if (!data['Join Type']) return {"image":"ex_join.png","image_text":"Join"}; + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_hash_anti_join.png","image_text":"Hash Anti Join"}; + case 'Semi': return {"image":"ex_hash_semi_join.png","image_text":"Hash Semi Join"}; + default: return {"image":"ex_hash.png","image_text":String("Hash " + data['Join Type'] + " Join" )}; + } +}, +"HashAggregate" : {"image":"ex_aggregate.png","image_text":"Hash Aggregate"}, +"Index Only Scan" : function(data) { + return {"image":"ex_index_only_scan.png","image_text":data['Index Name']}; +}, +"Index Scan" : function(data) { + return {"image":"ex_index_scan.png","image_text":data['Index Name']}; +}, +"Index Scan Backword" : {"image":"ex_index_scan.png","image_text":"Index Backward Scan"}, +"Limit" : {"image":"ex_limit.png","image_text":"Limit"}, +"LockRows" : {"image":"ex_lock_rows.png","image_text":"Lock Rows"}, +"Materialize" : {"image":"ex_materialize.png","image_text":"Materialize"}, +"Merge Append": {"image":"ex_merge_append.png","image_text":"Merge Append"}, +"Merge Join": function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_merge_anti_join.png","image_text":"Merge Anti Join"}; + case 'Semi': return {"image":"ex_merge_semi_join.png","image_text":"Merge Semi Join"}; + default: return {"image":"ex_merge.png","image_text":String("Merge " + data['Join Type'] + " Join" )}; + } +}, +"ModifyTable" : function(data) { + switch (data['Operaton']) { + case "insert": return { "image":"ex_insert.png", + "image_text":"Insert" + }; + case "update": return {"image":"ex_update.png","image_text":"Update"}; + case "Delete": return {"image":"ex_delete.png","image_text":"Delete"}; + } +}, +'Nested Loop' : function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_nested_loop_anti_join.png","image_text":"Nested Loop Anti Join"}; + case 'Semi': return {"image":"ex_nested_loop_semi_join.png","image_text":"Nested Loop Semi Join"}; + default: return {"image":"ex_nested.png","image_text":"Nested Loop " + data['Join Type'] + " Join"}; + } +}, +"Recursive Union" : {"image":"ex_recursive_union.png","image_text":"Recursive Union"}, +"Result" : {"image":"ex_result.png","image_text":"Result"}, +"Sample Scan" : {"image":"ex_scan.png","image_text":"Sample Scan"}, +"Scan" : {"image":"ex_scan.png","image_text":"Scan"}, +"Seek" : {"image":"ex_seek.png","image_text":"Seek"}, +"SetOp" : function(data) { + var strategy = data['Strategy'], + command = data['Command']; + + if(strategy == "Hashed") { + if(command.startsWith("Intersect")) { + if(command == "Intersect All") + return {"image":"ex_hash_setop_intersect_all.png","image_text":"Hashed Intersect All"}; + return {"image":"ex_hash_setop_intersect.png","image_text":"Hashed Intersect"}; + } + else if (command.startsWith("Except")) { + if(command == "Except All") + return {"image":"ex_hash_setop_except_all.png","image_text":"Hashed Except All"}; + return {"image":"ex_hash_setop_except.png","image_text":"Hash Except"}; + } + return {"image":"ex_hash_setop_unknown.png","image_text":"Hashed SetOp Unknown"}; + } + return {"image":"ex_setop.png","image_text":"SetOp"}; +}, +"Seq Scan": function(data) { + return {"image":"ex_scan.png","image_text":data['Relation Name']}; +}, +"Subquery Scan" : {"image":"ex_subplan.png","image_text":"SubQuery Scan"}, +"Sort" : {"image":"ex_sort.png","image_text":"Sort"}, +"Tid Scan" : {"image":"ex_tid_scan.png","image_text":"Tid Scan"}, +"Unique" : {"image":"ex_unique.png","image_text":"Unique"}, +"Values Scan" : {"image":"ex_values_scan.png","image_text":"Values Scan"}, +"WindowAgg" : {"image":"ex_window_aggregate.png","image_text":"Window Aggregate"}, +"WorkTable Scan" : {"image":"ex_worktable_scan.png","image_text":"WorkTable Scan"}, +"Undefined" : {"image":"ex_unknown.png","image_text":"Undefined"}, +} + +// Some predefined constants used to calculate image location and its border +var pWIDTH = pHEIGHT = 100. + IMAGE_WIDTH = IMAGE_HEIGHT = 50; +var offsetX = 200, + offsetY = 60; +var ARROW_WIDTH = 10, + ARROW_HEIGHT = 10, + DEFAULT_ARROW_SIZE = 2; +var TXT_ALLIGN = 5, + TXT_SIZE = "15px"; +var TOTAL_WIDTH = undefined, + TOTAL_HEIGHT = undefined; +var xMargin = 25, + yMargin = 25; +var MIN_ZOOM_FACTOR = 0.01, + MAX_ZOOM_FACTOR = 2, + INIT_ZOOM_FACTOR = 1; + ZOOM_RATIO = 0.05; + + +// Backbone model for each plan property of input JSON object +var PlanModel = Backbone.Model.extend({ + defaults: { + "Plans": [], + level: [], + "image": undefined, + "image_text": undefined, + xpos: undefined, + ypos: undefined, + width: pWIDTH, + height: pHEIGHT + }, + parse: function(data) { + var idx = 1, + lvl = data.level = data.level || [idx], + plans = [], + node_type = data['Node Type'], + // Calculating relative xpos of current node from top node + xpos = data.xpos = data.xpos - pWIDTH, + // Calculating relative ypos of current node from top node + ypos = data.ypos, + maxChildWidth = 0; + + data['width'] = pWIDTH; + data['height'] = pHEIGHT; + + /* + * calculating xpos, ypos, width and height if current node is a subplan + */ + if (data['Parent Relationship'] === "SubPlan") { + data['width'] += (xMargin * 2) + (xMargin / 2); + data['height'] += (yMargin * 2); + data['ypos'] += yMargin; + xpos -= xMargin; + ypos += yMargin; + } + + if(node_type.startsWith("(slice")) + node_type = node_type.substring(0,7); + + // Get the image information for current node + var mapperObj = (_.isFunction(imageMapper[node_type]) && + imageMapper[node_type].apply(undefined, [data])) || + imageMapper[node_type] || 'Undefined'; + + data["image"] = mapperObj["image"]; + data["image_text"] = mapperObj["image_text"]; + + // Start calculating xpos, ypos, width and height for child plans if any + if ('Plans' in data) { + + data['width'] += offsetX; + + _.each(data['Plans'], function(p) { + var level = _.clone(lvl), + plan = new PlanModel(); + + level.push(idx); + plan.set(plan.parse(_.extend( + p, { + "level": level, + xpos: xpos - offsetX, + ypos: ypos + }))); + + if (maxChildWidth < plan.get('width')) { + maxChildWidth = plan.get('width'); + } + + var childHeight = plan.get('height'); + + if (idx !== 1) { + data['height'] = data['height'] + childHeight + offsetY; + } else if (childHeight > data['height']) { + data['height'] = childHeight; + } + ypos += childHeight + offsetY; + + plans.push(plan); + idx++; + }); + } + + // Final Width and Height of current node + data['width'] += maxChildWidth; + data['Plans'] = plans; + + return data; + }, + + /* + * Required to parse and include non-default params of + * plan into backbone model + */ + toJSON: function(non_recursive) { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (non_recursive) { + delete res['Plans']; + } else { + var plans = []; + _.each(res['Plans'], function(p) { + plans.push(p.toJSON()); + }); + res['Plans'] = plans; + } + return res; + }, + + // Draw an arrow to parent node + drawPolyLine: function(g, startX, startY, endX, endY, opts, arrowOpts) { + // Calculate end point of first starting straight line (startx1, starty1) + // Calculate start point of 2nd straight line (endx1, endy1) + var midX1 = startX + ((endX - startX) / 3), + midX2 = startX + (2 * ((endX - startX) / 3)); + + //create arrow head + var arrow = g.polygon( + [0, ARROW_HEIGHT, + (ARROW_WIDTH / 2),ARROW_HEIGHT, + (ARROW_HEIGHT / 4), 0, + 0, ARROW_WIDTH] + ).transform("r90"); + var marker = arrow.marker( + 0, 0, ARROW_WIDTH, ARROW_HEIGHT, 0, (ARROW_WIDTH / 2) + ).attr(arrowOpts); + + // First straight line + g.line( + startX, startY, midX1, startY + ).attr(opts); + + // Diagonal line + g.line( + midX1-1, startY, midX2, endY + ).attr(opts); + + // Last straight line + var line = g.line( + midX2, endY, endX, endY + ).attr(opts); + line.attr({markerEnd: marker}) + }, + + // Draw image, its name and its tooltip + draw: function(s, xpos, ypos, pXpos, pYpos, graphContainer, toolTipContainer) { + var g = s.g(); + var currentXpos = xpos + this.get('xpos') , + currentYpos = ypos + this.get('ypos'), + isSubPlan = (this.get('Parent Relationship') === "SubPlan"); + + // Draw the subplan rectangle + if (isSubPlan) { + g.rect( + currentXpos - this.get('width') + pWIDTH + xMargin, + currentYpos - yMargin, + this.get('width') - xMargin, + this.get('height'), 5 + ).attr({ + stroke: '#444444', + 'strokeWidth': 1.2, + fill: 'gray', + fillOpacity: 0.2 + }); + + //provide subplan name + var text = g.text( + currentXpos + pWIDTH - ( this.get('width') / 2) - xMargin, + currentYpos + pHEIGHT - (this.get('height') / 2) - yMargin, + this.get('Subplan Name') + ).attr({ + fontSize: TXT_SIZE, "text-anchor":"start", + fill: 'red' + }); + } + + // Draw the actual image for current node + var image = g.image( + pgExplain.prefix + this.get('image'), + currentXpos + (pWIDTH - IMAGE_WIDTH) / 2, + currentYpos + (pHEIGHT - IMAGE_HEIGHT) / 2, + IMAGE_WIDTH, + IMAGE_HEIGHT + ); + + // Draw tooltip + var image_data = this.toJSON(); + image.mouseover(function(evt){ + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + var tooltip = $('<table></table>',{ + class: "pgadmin-tooltip-table" + }).appendTo(toolTipContainer); + _.each(image_data, function(value,key) { + if(key !== 'image' && key !== 'Plans' && + key !== 'level' && key !== 'image' && + key !== 'image_text' && key !== 'xpos' && + key !== 'ypos' && key !== 'width' && + key !== 'height') { + tooltip.append( '<tr><td class="label explain-tooltip">' + key + '</td><td class="label explain-tooltip-val">' + value + '</td></tr>' ); + }; + }); + + var zoomFactor = graphContainer.data('zoom-factor'); + + // Calculate co-ordinates for tooltip + var toolTipX = ((currentXpos + pWIDTH) * zoomFactor - graphContainer.scrollLeft()); + var toolTipY = ((currentYpos + pHEIGHT) * zoomFactor - graphContainer.scrollTop()); + + // Recalculate x.y if tooltip is going out of screen + if(graphContainer.width() < (toolTipX + toolTipContainer[0].clientWidth)) + toolTipX -= (toolTipContainer[0].clientWidth + (pWIDTH*zoomFactor)); + //if(document.children[0].clientHeight < (toolTipY + toolTipContainer[0].clientHeight)) + if(graphContainer.height() < (toolTipY + toolTipContainer[0].clientHeight)) + toolTipY -= (toolTipContainer[0].clientHeight + ((pHEIGHT/2)*zoomFactor)); + + toolTipX = toolTipX < 0 ? 0 : (toolTipX); + toolTipY = toolTipY < 0 ? 0 : (toolTipY); + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({'opacity': '0.8'}); + toolTipContainer.css('left', toolTipX); + toolTipContainer.css( 'top', toolTipY); + }); + + // Remove tooltip when mouse is out from node's area +// image.mouseout(function() { +// toolTipContainer.empty(); +// toolTipContainer.css({'opacity': '0'}); +// toolTipContainer.css('left', 0); +// toolTipContainer.css( 'top', 0); +// }); + + // Draw text below the node + var label = g.g(); + g.multitext( + currentXpos + (pWIDTH / 2), + currentYpos + pHEIGHT - TXT_ALLIGN, + this.get('image_text'), + 150, + {"font-size": TXT_SIZE ,"text-anchor":"middle"} + ); + + // Draw Arrow to parent only its not the first node + if (!_.isUndefined(pYpos)) { + var startx = currentXpos + pWIDTH; + var starty = currentYpos + (pHEIGHT / 2); + var endx = pXpos - ARROW_WIDTH; + var endy = pYpos + (pHEIGHT / 2); + var start_cost = this.get("Startup Cost"), + total_cost = this.get("Total Cost"); + var arrow_size = DEFAULT_ARROW_SIZE; + // Calculate arrow width according to cost of a particular plan + if(start_cost != undefined && total_cost != undefined) { + var arrow_size = Math.round(Math.log((start_cost+total_cost)/2 + start_cost)); + arrow_size = arrow_size < 1 ? 1 : arrow_size > 10 ? 10 : arrow_size; + } + + + var arrow_view_box = [0, 0, 2*ARROW_WIDTH, 2*ARROW_HEIGHT]; + var opts = {stroke: "#000000", strokeWidth: arrow_size + 1}, + subplanOpts = {stroke: "#866486", strokeWidth: arrow_size + 1}, + arrowOpts = {viewBox: arrow_view_box.join(" ")}; + + // Draw an arrow from current node to its parent + this.drawPolyLine( + g, startx, starty, endx, endy, + isSubPlan ? subplanOpts : opts, arrowOpts + ); + } + + var plans = this.get('Plans'); + + // Draw nodes for current plan's children + _.each(plans, function(p) { + p.draw(s, xpos, ypos, currentXpos, currentYpos, graphContainer, toolTipContainer); + }); + } +}); + +// Main backbone model to store JSON object +var MainPlanModel = Backbone.Model.extend({ + defaults: { + "Plan": undefined, + xpos: 0, + ypos: 0, + }, + initialize: function() { + this.set("Plan", new PlanModel()); + }, + + // Parse the JSON data and fetch its children plans + parse: function(data) { + if (data && 'Plan' in data) { + var plan = this.get("Plan"); + plan.set( + plan.parse( + _.extend( + data['Plan'], { + xpos: 0, + ypos: 0 + }))); + + data['xpos'] = 0; + data['ypos'] = 0; + data['width'] = plan.get('width') + (xMargin * 2); + data['height'] = plan.get('height') + (yMargin * 2); + + delete data['Plan']; + } + + return data; + }, + toJSON: function() { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (res.Plan) { + res.Plan = res.Plan.toJSON(); + } + + return res; + }, + draw: function(s, xpos, ypos, graphContainer, toolTipContainer) { + var g = s.g(); + + //draw the border + g.rect( + 0, 0, this.get('width') - 10, this.get('height') - 10, 5 + ).attr({ + stroke: '#FFEBCD', 'strokeWidth': 1.2, + fill: '#FFF8DC', fillOpacity: 0.5 + }); + + //Fetch total width, height + TOTAL_WIDTH = this.get('width'); + TOTAL_HEIGHT = this.get('height'); + var plan = this.get('Plan'); + + //Draw explain graph + plan.draw(g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer); + } +}); + +// Parse and draw full graphical explain +_.extend( + pgExplain, { + // Assumption container is a jQuery object + DrawJSONPlan: function(container, plan) { + var my_plans = []; + container.empty(); + var curr_zoom_factor = 1.0; + + var zoomArea =$('<div></div>', { + class: 'pg-explain-zoom-area btn-group', + role: 'group' + }).appendTo(container), + zoomInBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom in' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-search-plus' + })), + zoomToNormal = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom to original' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-arrows-alt' + })) + zoomOutBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom out' + }).appendTo(zoomArea).append( + $('<i></i>', { + class: 'fa fa-search-minus' + })); + + // Main div to be drawn all images on + var planDiv = $('<div></div>', + {class: "pgadmin-explain-container"} + ).appendTo(container), + // Div to draw tool-tip on + toolTip = $('<div></div>', + {id: "toolTip", + class: "pgadmin-explain-tooltip" + } + ).appendTo(container); + toolTip.empty(); + planDiv.data('zoom-factor', curr_zoom_factor); + + var w = 0, h = 0, + x = xMargin, h = yMargin; + + _.each(plan, function(p) { + var main_plan = new MainPlanModel(); + + // Parse JSON data to backbone model + main_plan.set(main_plan.parse(p)); + w = main_plan.get('width'); + h = main_plan.get('height'); + + var s = Snap(w, h), + $svg = $(s.node).detach(); + planDiv.append($svg); + + main_plan.draw(s, w - xMargin, yMargin, planDiv, toolTip); + + var initPanelWidth = planDiv.width(), + initPanelHeight = planDiv.height(); + + /* + * Scale graph in case its width is bigger than panel width + * in which the graph is displayed + */ + if(initPanelWidth < w) { + var width_ratio = initPanelWidth / w; + + curr_zoom_factor = width_ratio; + curr_zoom_factor = curr_zoom_factor < MIN_ZOOM_FACTOR ? MIN_ZOOM_FACTOR : curr_zoom_factor; + curr_zoom_factor = curr_zoom_factor > INIT_ZOOM_FACTOR ? INIT_ZOOM_FACTOR : curr_zoom_factor; + + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + } + + zoomInBtn.on('click', function(e){ + curr_zoom_factor = ((curr_zoom_factor + ZOOM_RATIO) > MAX_ZOOM_FACTOR) ? MAX_ZOOM_FACTOR : (curr_zoom_factor + ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomInBtn.blur(); + }); + + zoomOutBtn.on('click', function(e) { + curr_zoom_factor = ((curr_zoom_factor - ZOOM_RATIO) < MIN_ZOOM_FACTOR) ? MIN_ZOOM_FACTOR : (curr_zoom_factor - ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomOutBtn.blur(); + }); + + zoomToNormal.on('click', function(e) { + curr_zoom_factor = INIT_ZOOM_FACTOR; + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomToNormal.blur(); + }); + }); + } + }); + + return pgExplain; +}); diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index 4e08baf..c748900 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -217,3 +217,9 @@ background: #5B9CEF; color: white; } + +.sql-editor-explain { + height: 100%; + width: 100%; + overflow: auto; +} diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index 3e9bc5c..6d777d5 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -1,9 +1,9 @@ define( - ['jquery', 'underscore', 'alertify', 'pgadmin', 'backbone', 'backgrid', 'codemirror', - 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line', - 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter', - 'bootstrap', 'pgadmin.browser', 'wcdocker'], - function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) { + ['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin', 'pgadmin.misc.explain', + 'backbone', 'backgrid', 'codemirror', 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', + 'codemirror/addon/selection/active-line', 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', + 'backgrid.filter', 'bootstrap', 'pgadmin.browser', 'wcdocker'], + function($, _, S, alertify, pgAdmin, pgExplain, Backbone, Backgrid, CodeMirror) { // Some scripts do export their object in the window only. // Generally the one, which do no have AMD support. @@ -160,6 +160,12 @@ define( "click #btn-auto-rollback": "on_auto_rollback", "click #btn-clear-history": "on_clear_history", "click .noclose": 'do_not_close_menu', + "click #btn-explain": "on_explain", + "click #btn-explain-analyze": "on_explain_analyze", + "click #btn-explain-verbose": "on_explain_verbose", + "click #btn-explain-costs": "on_explain_costs", + "click #btn-explain-buffers": "on_explain_buffers", + "click #btn-explain-timing": "on_explain_timing", "change .limit": "on_limit_change" }, @@ -218,10 +224,53 @@ define( '</button>', '<ul class="dropdown-menu dropdown-menu">', '<li>', + '<a id="btn-explain" href="#">', + '<span>{{ _('Explain') }}</span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-analyze" href="#">', + '<span>{{ _('Explain analyze') }}</span>', + '</a>', + '</li>', + '<li class="divider"></li>', + '<li class="dropdown-submenu dropdown-submenu">', + '<a href="#">{{ _('Explain Options') }}</a>', + '<ul class="dropdown-menu">', + '<li>', + '<a id="btn-explain-verbose" href="#" class="noclose">', + '<i class="explain-verbose fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Verbose') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-costs" href="#" class="noclose">', + '<i class="explain-costs fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Costs') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-buffers" href="#" class="noclose">', + '<i class="explain-buffers fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Buffers') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-timing" href="#" class="noclose">', + '<i class="explain-timing fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Timing') }} </span>', + '</a>', + '</li>', + '</ul>', + '</li>', + '<li class="divider"></li>', + '<li>', '<a id="btn-auto-commit" href="#" class="noclose">', '<i class="auto-commit fa fa-check" aria-hidden="true"></i>', '<span> {{ _('Auto Commit') }} </span>', '</a>', + '</li>', + '<li>', '<a id="btn-auto-rollback" href="#" class="noclose">', '<i class="auto-rollback fa fa-check visibility-hidden" aria-hidden="true"></i>', '<span> {{ _('Auto Rollback') }} </span>', @@ -378,7 +427,7 @@ define( height:'100%', isCloseable: false, isPrivate: true, - content: '<div class="sql-editor-explian"></div>' + content: '<div class="sql-editor-explain"></div>' }) var messages = new pgAdmin.Browser.Panel({ @@ -770,6 +819,79 @@ define( self.handler ); }, + + // Callback function for explain button click. + on_explain: function() { + var self = this; + + // Trigger the explain signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain', + self, + self.handler + ); + }, + + // Callback function for explain analyze button click. + on_explain_analyze: function() { + var self = this; + + // Trigger the explain analyze signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-analyze', + self, + self.handler + ); + }, + + // Callback function for explain option "verbose" button click + on_explain_verbose: function() { + var self = this; + + // Trigger the explain "verbose" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-verbose', + self, + self.handler + ); + }, + + // Callback function for explain option "costs" button click + on_explain_costs: function() { + var self = this; + + // Trigger the explain "costs" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-costs', + self, + self.handler + ); + }, + + // Callback function for explain option "buffers" button click + on_explain_buffers: function() { + var self = this; + + // Trigger the explain "buffers" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-buffers', + self, + self.handler + ); + }, + + // Callback function for explain option "timing" button click + on_explain_timing: function() { + var self = this; + + // Trigger the explain "timing" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-timing', + self, + self.handler + ); + }, + do_not_close_menu: function(ev) { ev.stopPropagation(); } @@ -834,6 +956,12 @@ define( self.on('pgadmin-sqleditor:button:download', self._download, self); self.on('pgadmin-sqleditor:button:auto_rollback', self._auto_rollback, self); self.on('pgadmin-sqleditor:button:auto_commit', self._auto_commit, self); + self.on('pgadmin-sqleditor:button:explain', self._explain, self); + self.on('pgadmin-sqleditor:button:explain-analyze', self._explain_analyze, self); + self.on('pgadmin-sqleditor:button:explain-verbose', self._explain_verbose, self); + self.on('pgadmin-sqleditor:button:explain-costs', self._explain_costs, self); + self.on('pgadmin-sqleditor:button:explain-buffers', self._explain_buffers, self); + self.on('pgadmin-sqleditor:button:explain-timing', self._explain_timing, self); if (self.is_query_tool) { self.gridView.query_tool_obj.refresh(); @@ -1083,14 +1211,28 @@ define( // Show message in message and history tab in case of query tool self.total_time = self.get_query_run_time(self.query_start_time, self.query_end_time); - self.update_msg_history(true, "", false); + //self.update_msg_history(true, "", false); var message = 'Total query runtime: ' + self.total_time + '\n' + self.rows_affected + ' rows retrieved.'; $('.sql-editor-message').text(message); - // Add the data to the collection and render the grid. - self.collection.add(data.result, {parse: true}); - self.gridView.render_grid(self.collection, self.columns); - self.gridView.data_output_panel.focus(); + /* Add the data to the collection and render the grid. + * In case of Explain draw the graph on explain panel + * and add json formatted data to collection and render. + */ + var explain_data_array = []; + if('QUERY PLAN' in data.result[0] && _.isObject(data.result[0]['QUERY PLAN'])) { + var explain_data = {'QUERY PLAN' : JSON.stringify(data.result[0]['QUERY PLAN'], null, 2)}; + explain_data_array.push(explain_data); + self.gridView.explain_panel.focus(); + pgExplain.DrawJSONPlan($('.sql-editor-explain'), data.result[0]['QUERY PLAN']); + self.collection.add(explain_data_array, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + } + else { + self.collection.add(data.result, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + self.gridView.data_output_panel.focus(); + } // Hide the loading icon self.trigger('pgadmin-sqleditor:loading-icon:hide'); @@ -1816,16 +1958,11 @@ define( // This function will fetch the sql query from the text box // and execute the query. - _execute: function () { + _execute: function (explain_prefix) { var self = this, sql = '', history_msg = ''; - self.trigger( - 'pgadmin-sqleditor:loading-icon:show', - '{{ _('Initializing the query execution!') }}' - ); - /* If code is selected in the code mirror then execute * the selected part else execute the complete code. */ @@ -1835,6 +1972,17 @@ define( else sql = self.gridView.query_tool_obj.getValue(); + // If it is an empty query, do nothing. + if (sql.length <= 0) return; + + self.trigger( + 'pgadmin-sqleditor:loading-icon:show', + '{{ _('Initializing the query execution!') }}' + ); + + if (explain_prefix != undefined) + sql = explain_prefix + ' ' + sql; + self.query_start_time = new Date(); self.query = sql; self.rows_affected = 0; @@ -2153,6 +2301,66 @@ define( alertify.alert('Auto Commit Error', msg); } }); + }, + + // This function will + _explain: function() { + var self = this; + var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + // No need to check for buffers and timing option value in explain + var explain_query = 'EXPLAIN (FORMAT JSON, ANALYZE OFF, VERBOSE %s, COSTS %s, BUFFERS OFF, TIMING OFF) '; + explain_query = S(explain_query).sprintf(verbose, costs).value(); + self._execute(explain_query); + }, + + // This function will + _explain_analyze: function() { + var self = this;var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var buffers = $('.explain-buffers').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var timing = $('.explain-timing').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + var explain_query = 'Explain (FORMAT JSON, ANALYZE ON, VERBOSE %s, COSTS %s, BUFFERS %s, TIMING %s) '; + explain_query = S(explain_query).sprintf(verbose, costs, buffers, timing).value(); + self._execute(explain_query); + }, + + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + if ($('.explain-verbose').hasClass('visibility-hidden') === true) + $('.explain-verbose').removeClass('visibility-hidden'); + else { + $('.explain-verbose').addClass('visibility-hidden'); + } + }, + + // This function will toggle "costs" option in explain + _explain_costs: function() { + if ($('.explain-costs').hasClass('visibility-hidden') === true) + $('.explain-costs').removeClass('visibility-hidden'); + else { + $('.explain-costs').addClass('visibility-hidden'); + } + }, + + // This function will toggle "buffers" option in explain + _explain_buffers: function() { + if ($('.explain-buffers').hasClass('visibility-hidden') === true) + $('.explain-buffers').removeClass('visibility-hidden'); + else { + $('.explain-buffers').addClass('visibility-hidden'); + } + }, + + // This function will toggle "timing" option in explain + _explain_timing: function() { + if ($('.explain-timing').hasClass('visibility-hidden') === true) + $('.explain-timing').removeClass('visibility-hidden'); + else { + $('.explain-timing').addClass('visibility-hidden'); + } } } ); ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-09 18:26 Sanket Mehta <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-05-09 18:26 UTC (permalink / raw) To: Ashesh Vashi <[email protected]>; +Cc: pgadmin-hackers Hi, Please ignore previous patch as there was an error in it. Error: Tooltip was not getting disappear when user moves cursor out of image. I have attached a proper patch with this mail. Please consider it for testing. Regards, Sanket Mehta Sr Software engineer Enterprisedb On Mon, May 9, 2016 at 8:49 PM, Sanket Mehta <[email protected]> wrote: > Hi, > > PFA revised patch according to Ashesh's comments. > Please find my response inline. > > I am currently adding minimap feature in graphical explain. > I will send a new patch for the same. > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > > On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi < > [email protected]> wrote: > >> Hi Sanket, >> >> Please find the review comments. >> - Please add the missing 'explain.css'. >> > Done > >> - The application should be smart enough to handle conflict in options. >> i.e. >> Buffer is not a valid options without EXPLAIN ANALYZE. >> > Done > >> - A statement having EXPLAIN keywords with different format should at >> least render the output in the data-grid. >> i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; >> > Done > >> - Please use the keywords used in the EXPLAIN statement in capital. >> > Done > >> - Explain should not work with empty string. >> > Done > >> - Font size in the tooltip is very small. >> > Done > >> >> > - Smoothing the zoom functionality. >> > Minimap will be added and zoom functionality will be removed. So it is > ignored. > > - Arrow marker is hardly visible. >> > Done. > >> >> >> -- >> >> Thanks & Regards, >> >> Ashesh Vashi >> EnterpriseDB INDIA: Enterprise PostgreSQL Company >> <http://www.enterprisedb.com; >> >> >> *http://www.linkedin.com/in/asheshvashi* >> <http://www.linkedin.com/in/asheshvashi; >> >> On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < >> [email protected]> wrote: >> >>> Hi, >>> >>> This patch includes the patch sent earlier for stand alone graphical >>> explain. >>> >>> And also "horizontal lines are not proper" bug is fixed in the same >>> which was reported by Dave in previous patch. >>> >>> Regards, >>> Sanket Mehta >>> Sr Software engineer >>> Enterprisedb >>> >>> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >>> [email protected]> wrote: >>> >>>> Hi Team, >>>> >>>> PFA the first patch for graphical explain integrated in sql editor. >>>> >>>> Below are the few things which are different from previous patch which >>>> was sent for stand alone graphical explain. >>>> >>>> - Now user can select Explain/Explain Analyze with four optional >>>> properties (Verbose, costs, timing and buffers) >>>> >>>> - Initially graph will be scale (according to only its width not >>>> height) to fit to screen so no blank space will be there in case of very >>>> large graph. >>>> >>>> - Along with zoom in/out button, "zoom to original" button is also >>>> provided, by clicking on which graph will be scale to its original size >>>> (not same as initial one which is according to screen size). >>>> >>>> Please do review this patch and let me know in case you have any >>>> comments. >>>> >>>> >>>> Regards, >>>> Sanket Mehta >>>> Sr Software engineer >>>> Enterprisedb >>>> >>> >>> >> > -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] integrated_graphical_explainV4.patch (484.3K, 3-integrated_graphical_explainV4.patch) download | inline diff: diff --git a/libraries.txt b/libraries.txt index 9fcf755..ad1c004 100644 --- a/libraries.txt +++ b/libraries.txt @@ -27,3 +27,4 @@ backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all +Snap.svg 0.4.1 APACHE http://snapsvg.io/ diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index f461cbe..33c693e 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -6,28 +6,59 @@ # This software is released under the PostgreSQL Licence # ########################################################################## - """A blueprint module providing utility functions for the application.""" -import datetime -from flask import session, current_app +from flask import url_for, render_template from pgadmin.utils import PgAdminModule import pgadmin.utils.driver as driver +import config MODULE_NAME = 'misc' -# Initialise the module -blueprint = PgAdminModule(MODULE_NAME, __name__, - url_prefix='') +class MiscModule(PgAdminModule): -########################################################################## -# A special URL used to "ping" the server -########################################################################## + def get_own_javascripts(self): + scripts = [{ + 'name': 'pgadmin.misc.explain', + 'path': url_for('misc.index') + 'explain/explain', + 'preloaded': False + },{ + 'name': 'snap.svg', + 'path': url_for( + 'misc.static', filename='explain/js/' + ( + 'snap.svg' if config.DEBUG else 'snap.svg-min' + )), + 'preloaded': False + }] + return scripts + + def get_own_stylesheets(self): + stylesheets = [] + stylesheets.append(url_for('misc.static', filename='explain/css/explain.css')) + return stylesheets + # Initialise the module +blueprint = MiscModule(MODULE_NAME, __name__, static_url_path="/static") + + ########################################################################## + # A special URL used to "ping" the server + ########################################################################## + [email protected]("/") +def index(): + return '' @blueprint.route("/ping", methods=('get', 'post')) def ping(): - """Generate a "PING" response to indicate that the server is alive.""" - driver.ping() + driver.ping() + +def demo(): + return render_template('demo_explain.html') + [email protected]("/explain/explain.js") +def explain_js(): + return render_template("explain/js/explain.js") - return "PING" [email protected]("/sample") +def sample(): + return render_template('sample.html') diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css new file mode 100644 index 0000000..49a4bc4 --- /dev/null +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -0,0 +1,56 @@ +.pg-explain-zoom-area { + position: absolute; + top: 5px; + left: 5px; + opacity: 0.5; + cursor: pointer; +} + +.pg-explain-zoom-btn { + top: 5px; + min-width: 25px; + cursor: pointer; + border: 1px solid transparent; +} + +.pg-explain-zoom-area:hover { + opacity: 1; +} + +.explain-tooltip { + display: table-cell; + text-align: left; + white-space: nowrap; + line-height: 10px !important; + padding: 2px !important; + font-size: small; +} + +td.explain-tooltip-val { + display: table-cell; + text-align: left; + white-space: pre-wrap; + font-size: smaller; +} + +.pgadmin-explain-tooltip { + position: absolute; + padding:5px; + border: 1px solid white; + opacity:0; + color: cornsilk; + background-color: #010125; +} + +.pgadmin-tooltip-table { + border-collapse: collapse; + border-spacing: 1px; + top: auto; + left: auto; +} + +.pgadmin-explain-container { + height: 100%; + width: 100%; + overflow: auto; +} \ No newline at end of file diff --git a/web/pgadmin/misc/static/explain/img/ex_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe75d909f5092c4d3ba8978c75fbc57d7f606d GIT binary patch literal 574 zcmV-E0>S->P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10lP^=K~!jg?U_w#!!Qs=pNrR76nc`JAiEyfyPUu$F?5lg!9`tE zrVdorjI6O#*B=N1Q4~GTk7uODImZ$7QhEcqbb{2T!+^AsNlnvqz}0v!OZCpVcg+u) zSl03oH-ylcGy!)Fj09u=UN>$mMIX+&H|b<ajP!gzp{f<N2t38e1(}OYz(X)^Z9SDm zaL$Pb&;cXx85twc3D+9}YYwWtX(n61tgLAZVhA&A0ZDox`m}f_o&;Lp=3^|TZAm4? zB8D-uw2Hk&77xL~GD+H8Yh{L+-D~onRU64N$mC{z9Z`Z<4$%uyDn(tUuBBqiTE>@* zne6>YDVVIT^|Y|u&2%+YKxQ4H!ZKN8+Uk0kwJKPjW&<(>@$PjAe4RCOnSn%Nr0(=P zYi|fJ04V_hnL$cH0K3&%;sz_V=BgQD)cm$)2vvhs6@*_isdrBfc8kD{yg=7gktITF z+PGFu2!0OeLWgu>5LFp3D9xourL!bQu%a?wd{rRqFIvi++{=Q!&>aaV%KTa{dS;2c z$5o3IhEOTyT37x61pK30-JX4KbAS7Pk<5;R_SRus>jbGyCrEAj0!#X?PWurOy8r+H M07*qoM6N<$f>VU-$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_append.png b/web/pgadmin/misc/static/explain/img/ex_append.png new file mode 100644 index 0000000000000000000000000000000000000000..017a2068b735f13cb89a3bcb2832e5880d17df56 GIT binary patch literal 1162 zcmV;51a<p~P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(LcQrnzUg(&?|IPgRl@0p)bM7=>}tvEZ_4YI+3|bM?Sj$mrrz?7)b5hj z@2}zW1*hRn!RZ^W<6Fh+V#n(^x8+d2=WEC4a+aaNk2du1$nfm9@9MSh>9q3g#qH&> z?c}iR<FN7S!|>?B>));G-mL1~tMBB$>*k;D>$d6On&{t|?&h=S+m`0ol<eWI<I<1f z(2eQZsp{jL=-rs*){^1Oi|N^?<kgYn(~#oMjOf><@94Ab;k?JHb@1lE=hUR;)1&O& zx!}r)-o=I9!-U<zg67eo-^hpM&!OhgqTIiL<j$Y(=D_CCqwCqW<jtPr%%0=Rp4+{D z+PZy)sbo@(8Kui)sL*Ju)oiZXakAicwdHz}mC<Hv(aX&7yuR$dzwOS>^3l=q!NTst z#P8G8^VQY#$jI=?$??j|@!8t--ro1u*Y)Ay_q@IAr>W+ss^`DI?yaxsud(UH#qY<+ z@3pq;x47%Lx$M-`^vB2WiI(>{00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0zpYcK~zY`?U3tJ5>Xh&?SzGeqJ$LLD=fGO%SB*ek((>YO)i2W3vOk#CSYi4 znRfSIZ+9mfuyZIJXZldjhj-?kd4K0Q&oeUeU#e~(MZ}3i&`phI^cK3U)oRDk*qyt& zaWp=m*H5C!DTCo2!Xg@@(Kw2xO(xTQ^uTO3>(InQtyYhwW@dB-G{|N8&s`p=e<n^G z0<#v2W%goPDar;m`yB0nd8dnU0~WD(JRXZWy+HYV3x2Q%f<YFXp-`9`j6@<<8Ch7g z109S;oxp^{vG^dw8;L|H@Gk}eG_cV`k^ych7US{Aj}#QOtfZjT6pWn09q0KJ7I_Sc zh!gMP^;&1a=J(qj;9yzj3b;8go`O_5oyp=qCa3T%U!+JRLvo5(EXPASzgj5bk-lP+ zO0n@=u9Sw%YN1djA(xBgOQn1U)(VwM6_42b_BpvF*6CW8Q^eI2nT;%D%hhV_+8T4v zEISV?48yr0#q(+T{k3Ab2DQz)fOi2p8cn$56iaG~e0~Fpl}e)u^=7jv;1M>FxKwPp z(r9dgKt_How%TaO#{-achU4Ux__UIuSXNThl@v8W5U#DUt7}W#B5ow&NzYaPMkJm- z`+3#B5v1H~KNqnZ(M8-Adt7=qvQOWu;_p1vqZcA^BYthzl84euNfB}45NYSt?ruwJ zclP#POWpm0H;2+;tKB}5j=J6Bw-Oe4cXIOnRO+0aefTJS`uyeVj?_BsblTFl^ZkS4 zzljW=<qD1clll(R-{b2g;$(6F001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@z zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUh cIxsdXFf}?bFv^!ztN;K207*qoM6N<$g1#AbUjP6A literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_and.png b/web/pgadmin/misc/static/explain/img/ex_bmp_and.png new file mode 100644 index 0000000000000000000000000000000000000000..64d5869dcfcf9d94d031fa068cff93ea929180b2 GIT binary patch literal 1006 zcmV<K0}=d*P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004)P)t-smD2kF z003rd(R6flb#--ic6N7ncY1nyHi*G{dwYC*e13j@fPjF4f`WsCgM@^HhlhuVh=_}e zi;azqj*gCGmC%omkC2d%k&%&&j=z$UlEIHQm6er`lHGcqshOFXoSdAVo}QbW#Gjv^ zrlzK+r>D86a;T`NPQK>5s&lKWtGldpyRCMut*u(Y=dP}<ys&q#udltad8@4GzOs6W zx!ba`vSh{Rx3{;mwCZuo?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?Zd;v-NJ*w!S2S! z#*5VM-^PaD$cK{E@5aaP;L3^0%F2}3@Z-y#<IJAq&7R`WjpWXs%+2x5&hq8Zq2|$| z)6>(Y-ty(vljhW<)z#JK)upZ9^VHPy=+~y`*Qe^(w&~ia>DsB<+S=*ds_NXT>)W{8 z+}z#W-Rs`0?A^KE-rnrst?b~g?cclJ-uCR`ui@e0?BlTF;^Ob*zvboS@aDkq=fUUa z=jrL`@$1Cu>gw?D@bU5S^78WY^Yiuf_4fAm`1ttw`T70*{r~^}C9&%N00001bW%=J z06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0q;pfK~zY`?UY$l6G0S(b8}-Di3kcP z+Oo)^h$4bwltoqvL?DD{Mjf_nBqD~O2?A~ymixDzo*9a*Gm})MC?7Zv{c`K8Gv{>Q zvDq$ko~o9(s?QF(wL!N4k*52GJqwax@WJEtiUu~Rr}eShD?&VOcaK*pj!Vugb=sg# zfY{%@e)DeKes;iqrqk&yCPD_D!r-C^Nk4<GWMRlx_z0E==`xVDE_fnFj<OJC>PwuJ zQ#!=9lF84TBBa*NRjVOi9LP1IA^nW2-@@fKw*1L<;8opaGaip`h_l>+MlB1G6SG9S z=+u$;BX}4UBk&Ro<O=>E`h+(O1ZE*><<f@Dv{HsEI<ou#?nSH``|ZN(SURV-%r>Ht zNXoo1qP+&hYdgl><kJ{stMHBkrzooyKsJ^Ng_cqlS=#YAjp3zO3@bPinuH0(v@xPG z-th~(T!n2MS(<=x#ngpg%P%#>ef9pot6A9mcrN5H3(-xi$?R{pAeQfQB&8_Is%c|H zG5v{QDc(Jx{2HTgO)iJ4;r-tV>{PR?%CelW*cUn`^~2;*7z$c$rLkbz!Q>%$6)bF# zgDMhW1^r<X!9XBkv6Uy4*H)f(3HbeC^EY-H@%KXSjQLiI5MN;~GdYo*S;9V_FI=R? cF7zMiA0?@qIju>9W&i*H07*qoM6N<$f<qfLO8@`> literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png new file mode 100644 index 0000000000000000000000000000000000000000..2657d8c39328bfc80751c60db9d3ab4341c0de35 GIT binary patch literal 1106 zcmV-Y1g-mtP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s00000 z003rd(Nc{WHi*Gol_FY@Wn`8)38~@|tKwvp&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPGu5^~NHbTAWN5AP#zUE86=}y7vTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q^_*?AyJGyuIvu(eH!N?S#?pz`^c> z)9|d;ZHv_Ik=5>!)$gv_amL5*l-Tf>+3~XAcCFUw%+2wj+wtexE9lxP&Cc@b+bZna zD(>4V@7yZ!+$!?iD)ihcx!dfw=Y00vDy`r1`Q0h{-6_=6^RD3Y``#)1-YNdxDZbwA zx$A$x-|oWT?z`@S?c-qY<6p($@9^Ybyzqqb<X`jTU&rI{$m8(y<zMvWU&`a~_2pmp z<zM*aU(4k2-rn~3=3n~eU(Mz6{N`W&=3mk0^3&+^^6H1w>GRa-^z`e8*6H;2>xcO3 zhu7-$`s|1O?1ujAhT-q`mEcQQ00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94 zoEQKA0&7V`K~zY`?Ud_N(?Ar(NfQ+@uBZsUQR*A(3k7^uiA_xlwb7<XX$T2Wl46zw z3Z<omf1TZggd}Y;GR`=D;C$H3?B=&;&b@cGr{_ffM12%iU&sC(Yu~pzN7RRBuO_}z z9SHSg=<4;C)SHp}k3Ldg#wI3zy8lp*uid=+whJ=U+k5r~HGFAc;3+jWJaTW6`U{t^ zEElbP-|8I2KEHnd^>^&(-vmu3&<E7Y<#G+wL{Y4Rx+F<;;36;16PJH@5PE-~#z=W; ziYWt;VNw#1SeBJN2=S2cA-lUa!Z3^o#8j#a5_H+w@gP!)Wi2G_L4sKv#G9fn%W}g- z`eRt9$y)*BIl%I*K9?(GoOF@xZQI4ZUy^0CDl3(yC(CW(0vV5!j_A!z8h-}~mT*$6 za2%)l5JX@-7#$sd_le%vpcj!ymO#PfbULko3dd#C2p5DnE;2^GRe;K6G8zcaf)Jd= zPSH>*C`D7%v}T}UXUKCdvcCQ&74!AQMsP2b2D)EWk&C8PTM^wqM7$}qY%Zrq%-GtR zg(zuUST%!@YA%<95iYB%7Gn28&1ADxp!<=IEX&Il;!V+l5Vj&_Y-#D(Gq$jB=z@FE z)OFo<X@_?I6h_E^1__=pLT79oBQrC<=I0lWMDj$zh?ucbsf$a&>(Y@0AyyV$hfa#N zVHoX*8Jn9s_Kewxb3cRzb}`Mpu<oOWZ+aR(egNk4c?ck1K*3ExD4Jn2MsLj~le1g2 zh42s<1wlYavFJkrE~R9$WV`UZ0SrM9%pelTlE5>D9%WyOJ=2@Tu2_G^GagZ~6a9ZW Y0Mz-{B6#`Cr~m)}07*qoM6N<$f){{JGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_index.png b/web/pgadmin/misc/static/explain/img/ex_bmp_index.png new file mode 100644 index 0000000000000000000000000000000000000000..23b9733b56792533e4db25ca9890a0a0140c6ff9 GIT binary patch literal 1172 zcmV;F1Z(?=P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004@P)t-s000{R z003rd(Nc{WHi*Gol_FY@Wn`8)45{LDla^$a&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPPu{MmZbjzYxL%irozv)iC=1#%sTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q|V#etORA+r5d~zJR>F?0eDg-NAx` z(d~rM?%l(Kz`^c>)9|d;ZQjL&i`4Gl$A^*C?%>FXlGX37+HuCm@8HUbl-Tg$%!-%U z@#4;m<IJA2;C8Ln>CDaX<<6kv(T?ZZE6vXG=Fy>}-SXtrk>=B+^4u!t)TFuF?6>E9 zt>5$1)bp<3^XA!==+~zI-YMzWr@r3px$A%D+?T-L?&;d7!r<=c-k9s!x9Z%g?c-qY z<6p($@9N#Gyzqqc<X`FGo9x}X$K&wG<M7Jk@a*8N%jEIi-uC(CU(Mz6?BlTi=3nmO zz3t_((dY8+=Caf1^Y7)q^6H1w>GRa-^w#P0@aMtr>9p7C_3`P${_KYG?Z)Bn_g>Mo zbpQYW0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_00N9jL_t(Y$L*BsQxZ`a zhh26nvhB^vO1oLo-JmFv5|N5XBA|_nRxB8D7XcMR7F@v#0{+$QVK1_a?Bq1l^uhPT z*_pHZ%x|7^ezOAuC-YBckU%rovwx?vFI&Y|#D{0EroRzA2=QcObo3?hX8iu6kHpu> z>6stWH^k%XH}AeZ0vXY2wKs^dOT)uYiOI3?do#per1Wz++u7&Wi~K6S(tLjX{>v}T z;kSB{)N>E0r_<>=v>S~^8`><(wn0K(oX0MI??T9f0}>%=uh*M~Mn0c!0Gmiet6d28 z5R)PM`wD~wHX4nVRZ@0$Wk@2yLNyu+bs<U@5fNNE7R_?GyeA<;8Z@WzTMFbFpyAi& z{3=ViitBI*+1Zh$RI5#B7K_EbE|=Tb1ze}Y#UZ!0Nc6mdd9k!$QS|wISsB6+XdX;V zOuhR=Zf=sx+~8h})31g?q2dvUJcUEVlnj&w#N$ape-{qnT{4-vU{TAaQZ>biox#sZ z$i~K>oS5uhcm(RXT&@m##cZ|)wNxxtQMr8q$pr#|oL~`iI2^P}$JW;+qy$+HkJ#<B zO3K=rgfNiu%+AIjVz=9ZDji#0?I5jEsnmj63|UlYnl7kxY-Q!x9a~xwQW&NMl}LoH zKp`0P7y91*DTMI1AI2EY!p2zyEfzD?w_{TXnV<i;jEAu>1GLR%4T9fnRv_|@#p7Km zwAE@sh{;5$bc{nfE(~(vEeaGxB~?1MxOnW2@ran>r>FuX-EMcX-|cfhzPUN{^8+Rv z=Ja_Bx6xp5_UjnAz2I^!Y?C5FnM@`(xD9edkrH>g;)f}e$!P3B6fSzyF}>u%TO^%M mr}D&xdVb?7Cw4Ob-~0w&gyX$CR{j?N0000<MNUMnLSTYde~VB6 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_or.png b/web/pgadmin/misc/static/explain/img/ex_bmp_or.png new file mode 100644 index 0000000000000000000000000000000000000000..c22fc31eee32e53abf634278f9d57751181f15c0 GIT binary patch literal 685 zcmV;e0#f~nP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700030P)t-s00000 z003B6SY~U{Hi*GwmC%ijzrl|-kCNSbo~fFenwy-&xu<eYzUI5CbGxi`yRCLw!RNfN zcfGNBtE}k0vU-WR+hoP)v$X2Ey1H@8?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?cKtI zz`^c|)b8KLhTq7ClGX3V$M4|EiImvz<IA4o%%0@Up5oAr<j$YW&GF67^3l=J<<Oz# z(W0i_^5xc(=G3I;)upZ9^VHPy=+~y`*Qe^(w&~ia>DsC3+^Xu_s_Wah>)x#F-MQ@G zt?b~g?cclJ-uCR`uk7Qn@8rMa<mB+?!0_k6@$1Cw?CkIF@AUNa|NsAqxAFG?0004W zQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkPM@d9MR7l6|)NN0KU=#*mj$o+0 zXGv;SRwxw`6%>^SK@x>8z5V~+lCW40^I>$hY<=+l#CCS=?A!_rGtXZp&xOfP4=T~1 zLLuDg&VhK#Q3h9{B+&*8S6f~eBpML~p(b&^vn6@U$0T2m#b{8Z5cd4&_~MEE7O~-9 zf*=_4G_tn|`*$&UE0u;Z3AUi@Ws_kpcNvpsxCSJ7EW-w!ByJ(e*z+DnG*V#06sAdo z57R(x899zKpx?3pi_}}3HCVOj1h#=r;0$csmirZ0vT%(JY|HXz-k5KiT_1Ogc>-+% z*I2g=Ed#gZrj<t0Z!rv`Kl8@=x~{vp_eDR1riLU<*hLa;LR4I1uBNJPc4P0=>MO1> z^3%t=s-pBVfBn$JPrOoxdMEQgMkXTi54I4blS&e|kfbNeaxb$nGU<)Y^N;cg@O4qi TF88uo00000NkvXXu0mjfLbGwY literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..e99f57478842f61cf0582433b659d37f0c532d5c GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_@3?!2S6O@1yXMj(LE06{PXIHn!e64$cEXI-` zzhDN3XE)M-9L@rd$YLPv0mg18v+aP48c!F;5RLO&CtC9zP~dS+JaMn}cL58V&ewnH znS#1o7niJ>^>*TX*`QzgMdD7POzPaTo+w<9uwpLL)1F%W#!IqdhoMSxhwp~0@cf02 zhkMjmROfZc`EZ)w`S;|i<*e@Qr8gQ^@9R11|6Rc8|AQ9IRLjSmUOFeWtM)%%ZozPh zRpl$&!*g?h?ocgpjVMV;EJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0 rRpn4L<mRVjrd2{T7+8WefK*!<m_an0njX3asDZ)L)z4*}Q$iB}@40B! literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_cte_scan.png b/web/pgadmin/misc/static/explain/img/ex_cte_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1d779372f7fd212d2096e7701b0f1af05a5297 GIT binary patch literal 1955 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_delete.png b/web/pgadmin/misc/static/explain/img/ex_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ca051cd5d01ee2f3ac17779b362999d82a9285b5 GIT binary patch literal 1129 zcmV-v1eW`WP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003^P)t-sKLD^> zTU+Qs2lh=8Hi*I5b0^MyED5RN(19;<mZ6f8lEIHQ*N;guwdHlD$Lf$-LA>b8qFCae zX-dH9$EtPXqi$Wq>SM<0Ysctl$n0**>~+oT+Pi++y?@)iiQK+`+`oW((eK>Bf`rlT z-NS=~)9~KJgx<x4-o}QE)b8KMhu_GEk=5?t$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc z&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+mlIGK+<<^tt)THOtrLN%f=Gm0!*QV&# zr{>z0>DZ^~*{J8-m+9K6>e;sG+p6o@x9HxP>fNgB+_>rBn(N-I?A^NS->vN4y6oVs z>f@a4-@EMLuI=Ev>g1j5;;-%DyzJw!?d7rW<i73ZvhL=y@8!Vo=D_dhv+wD(@aV$u z>B8{rw(;x4^6ka*?Z)%)$Yy(c-~a#s0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkV znw%H_00Om1L_t(Y$L*8bdl^v_#f8bG-PLL%nhMc~q#`mQ2qBD7)FomPgc62MQMdg6 zk3DnFFeXNthkjrCko~Zp{O0Vn_M*|e%s-g7lsHRO4WY~igJFl-+ccRDsDn>t^C@+@ zx4(Z*ogcZ~Uny0@u)e--pf-`3sE>NR-c0Qve4jen-Zs0bzx2v0yz^33L*QXJ96n67 z-|vrMEC|8~Mm*0Cfcyr)IFAhP?`wTY`?t5ZJrIhyTpRdgGF}BjOnw=S3Z#aS8bOKz z2)SI2hh{Q9MZQla-3-V`zlMK|wO1@6q@DYg<e?sq#VQh#$r!5>kiFpjXD)tV7tH|- zs+Ce#@?tf9p@%c(J&3b~b$3yv?^<i0Wd?NOY>az?FosdP&5vMEuU5Oz<v6Z0{jh=o zomQ*WZOAT~qKnHCa6!L6FYiCcNQh7@l3<f{sKzcYIN<z#Z+<Q&%wTg<1P9CGU@I5F zAO{7nm(GGl$rxFfd0BMP$!D`Im_IsL#iN4e&4xICNNma=3fVzdXx0akb}J=xi%ub* z??5Y^PBlQ;M@VO0uV|$Gl`d%HB7Jh~V&PGT0ag%FkH=9lh;qT8zW{lfrqhr*b~zs- z5-3Jml9U9SrB6;$kZ?Mkj5>n$=YC2mx@aL6sYC-BEW?yl5z?^_b4}Y?mYDns#}ztj z_&TfPMvVl^-a$DU3E!wMhWB5?9atqzKrRj$h&b%_kUD~kp+H#Yp(6@myWO?~!I3Hu z=Fs5?L&$Ek1=NvFHk)oKyp$u6@HJeA0)gu%65GN}d$-s()mK`n1iAvzJBEpt;U*Lc zp;rPv-<A4eq!>gQ2X<i-UHB{(%b7ZoaEZkr8pXlNh({e^(G{YSM(iRIu-Pm=I9ra~ vF;TQX(RmkF9*^hhiNtoF^RIlF|7m^$H0#Fus?kFU00000NkvXXu0mjfhwW63 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..acba49c4fbfd9b871444c9e8d528deda3a37dda4 GIT binary patch literal 1607 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 FV1m**ONRge literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_gather_motion.png b/web/pgadmin/misc/static/explain/img/ex_gather_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_group.png b/web/pgadmin/misc/static/explain/img/ex_group.png new file mode 100644 index 0000000000000000000000000000000000000000..8d5de31bc129a9abcf4a73e19a48739139f66271 GIT binary patch literal 1228 zcmV;-1T*`IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=(EA5f2CVejTwfiWOA0Fgt11U#9qOVHuUhw@a(tm>9z9h#qH&> z?c}iR<FN7S!|>?B?BK2I-mL1~tMBB$bEG!w=AY@{n&{q`?&h=R*_GtekmAse>DsC4 z<DBHxlHtsY>Di~^&Wz~SrlQAS@94Ab;k>5IWyh*@@aDkh)THLqqwL+ecBwj^wTIx! ziQdJ9-ou35!Gh+|q2I`d<<Fq3)@|IrfaJ}di@s3r=D_ROwzcJZ<IJAp%bvUMgW9`& zd$dE9%UpG!OlO!lj)kjcYthWj@w~q5zQ66y&+^gH^1{OI!^Q8@)brKV^vKBY$;t7` z%kkOT_1@n1*Vpyo;rG0~?5C;bsH*3`zwW@o?yaxsud(UH#qY<+@3pq;x47%Lx$Mi# z@y^cjz`^d+)bz*4@RF6$yGLoX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0)t6JK~zY`?UZR(+CUVB(*d`NQfXa6^~z!}1Oy^sF^V-vQ6PniB6gWpu~n<K z*4lmj>zxTpNrZFE={Y_9;C#4z;o;8n<_!#Ueg5^if#~TvJ0ZwowOV^nZ(o1^02;Vy zu?(WYUYl(Q4Gr7vw@^pKIx;e1MSTv3<2Jf8Iy!1WJp{L*;juA`9sTu|@d=i7GIzB* zcbx`ea%zfYVA|z!O*g08?e>7jJHz>4miG$*&>@5fk}cqxo11erraKf0N5CtJA`kxg zXjIZ8>{QT6K3YgD<|aru>;+DY$NeBgqlu&uVVO20Mv+K3EONld<MRSY3yFkmKo;vr z%VLRIaMZ#t5Q{)kmQw~~SwrptJzZxz;S5eXn_Jw|;E6=MKJf88zXAbCN~R#CDCt$u z5zCqTb(dHyv_vdKafVpTQ;S3*D}%DOp38&oS{ZE#LxT<JgH2|$1qIUUxtyxol6lbB z@+Vln5v*J&tfe8J%N0vHeP`xj-Nh5}&d_Jg`!|S1QnN@Ci&a%El?{n)noX>UfRE$& zSy&MSDF7*1R><$?^J*E&rLBr_%XS^%;`MqgXclXlMUhx+RjbvC5!ul?)~H8Yuxhbb zEkWfnGVy48hc@|gu%#mXatCCbFywBqAxIKQNmeuqm0E03i*lu6bQyolvg{M)DW<3E zG`wPq%cPn3+4J4qJzU%0fAJC@93H(o#>acL+6g{6I5>Tc4doBgcOSnwJ9~SM-(6h1 z|A0S!`uyc9{&xO-zlMMOJUluzB3ffiAkFe$9ch*S>MpJF|I(7_Iy;r$L}JbIn@VhR z$7Es@G5cI-#kS2oefq~wwp=~2>+`>z-(ue+J2o$;LI3~&C3HntbYx+4WjbSWWnpw> z05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppn qF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTX@`Go)g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash.png b/web/pgadmin/misc/static/explain/img/ex_hash.png new file mode 100644 index 0000000000000000000000000000000000000000..9f35c76538c3a41920a7b93b94bdf97443df7aa7 GIT binary patch literal 1169 zcmV;C1aA9@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001n zsbo@(8Fi+|Hi*HY#9nXB?oYw#V#exs&h4h&@<F}n38~^Nv*by<=84npY=q5bYthWj z@xa0E#>el?&hp;g_M^vPyuIzKtmw0}>eSTprp#qVzv+I_?y1pfi`DRv*YI-8?0nAc zpxg0|)b5kj@2}wVOTX!?)@^0T>qEQdP`>AE$LX%xagvqMa+aa8;C8`}HuUky@a(s= z<azV%$M5K~?&h-b>%{Eiu<YTk?BK2N=fUgdp10_I@9DMZ-I(RolH}8n>fNlm?Sban zmF(iL<I#@k+^W3rgyPSQ>Ds94;H~fF!0zF_pG#z^7Z=B>b%2f~b#^4RQ$FKkW936b z-9bUQ>wu4ZIPc`Y=+~#`)}`#;yM|jA(>_1o$cW#@hUV0yu-$XX5E0BgJmJiW-o%9F z(xSc&4#hh=;K_*H!-U<zg67eo%w1jR)~4*;x#rQL<<Oz)+qdxO!sgSY<j$b#*|yug zf7-fz<IJAizk%e<p5x1&-i$@K00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0!T?jK~zY`?UU<U5<wWn@pV8EQt5^jN;fSkZ!Z^txZea>#3ciXMG^ue5lb*` zBLBL(BnC@M_{lzaKFl*S`~03W=gh1~bf??Z7>o&i8z-E`2MDn+LnITE(kU`Ph=my< zli!=3;UOHsGB<N!4<_g`tKc-t-v&Vskw|g>!NW(76$6NJ2r~EN>D;qx<f=ddDj?lC zzfvATB(nK=DOmtDJSQ(+N?*MuQ;UmBZ^#ftCYQ_Kk_phjJ0f{M{b7O3OfD}k^&$OP zSQlBxWkuL!wbR&Yce&O%`5J+BAl-Rq6m~(aPN&nN7W801!-mmlLX-KU#frjNP-nB* zbf^P6IMC>HI?ZTyx!j(ABM$Jw28;N7n`m*n{ee-CEij_l=W|)m<M#(C9G=C&reF~^ z#ik`>#q9t^g?o`5n$u2q89~HPuuHQD{TVq$evdr}9gW5IqV%<k!Qp^7d|{C&ZS{Bp z2@Eq#a=+Jwj-`OFxEFRI^_BMcgKP@sAf3+iBOq2Pl`555t<kJ}Ti5ID_PBQove_IR z2<Gz)Cew$9g+65OuP&+V_amCh=Zi_q93GcW`jBWYcl6^=7L(b`W$A2&nV)Qm)AC8> zY=p)*2{p#QmtU5UXB!g~#e{J`Q!Sk0S*=#954-)4+s{4^DqlQEV)eLGs$i|rXr2#4 zu8J*k#g<F0Rt+y2&1QQT(pzk$)oRr6yvav+SrQb(rKlFlofH>!thd|kzAU`IGSb`9 zXpM~`UY7p|xp@{|V|TiBT>>)4pzcQhBc}iW03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfr*~9W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a4e9369fa78c6fa19bf5c7814f8a586aed5565 GIT binary patch literal 1571 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 VFfhuORjdF2002ovPDHLkV1kgxQ(pi8 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..0051f996783873a4a27db4b971135e95cac8d744 GIT binary patch literal 1452 zcmY+CSx}P)6on&<ilC9wDWY}j1EW==VG&s^MyMc>VE_dIWsf2%OOQ>VP^3a>#ezbi zQ$WfpN-;oW2^b&=k^l*WB?JiB_w`TyKVY?Ov`?Km=bn3K?)P@ef&wq>vfO70gTZ$B z`}qW$(($7$%uVxaUUo4IW>yn~4)ryiwS?^8pZAsxthkhpJ|kUEnO0vS%3>*s%xPsS z2k<7yY&!WTdW3!iaT!ycQNDmlo}HT35l7XO3C;8jz~MlDOvDm~m7Oo7J-u?muxfr@ zpW4Z+8|Svr5=g76*J7xhadTK|9F-Zn1z?W=#EU?ha)Ykg7?VO|88jh>7B!m<YlhB+ z+ihIKOFme=tgB-K^{c?37$i!dE}kC8*Y^qZlX7DhJFTT%m|NeG{<NMuQHSGZ&NB!^ z;v%k3I!Km}R=5~+lUn8L%?)9nD0kB+*n|W|{W4?{z}f(LBJsvL7vc+yV)2Gr{Z1in zFoNuUS%J~8tXEIz)ik||2I-d8IN-v9etFrj#(`wAO|24dG_VI%MS2w#P*Oqdl0sB3 z7yho1^%ArX0Ocg0m;^P88U<b>@6$+o03~@7;%^vuMm@JJ<aWoNJuAayg^%p>Gmnsy zuG1*Xb4;BYgOU392vO(P&!Kp6@p=_SEyk&Y-2;lk%6vCay<jj&HE-0dOV0b0N7*Ii z>@A6~WuE;;C#7g56s?$SP%?QaR1+n-c`~kT8uNVa*2|@o?lo)=KN~N}8`2cd*w{>1 zTTgj<YDFZyg1O@D{UE}YyxV#N4ySl{7?kr`5m_T5X@ui?`P^!3EZxhC>gh@L@R+)G zO(PhQvf3nzE#>#mKw1u{SyOTb#j{N!#xvnegJKyEY1bgl8X%hmqzq8Kx;j$0LMUJl z<qK%_8X-v|7+3Q~)m)Q^fP}#wDqs)hYxrZTbs`|9t4#~%jZRFLv+$sL4Uo=)sui7h z#-L;~yHiyh($Tl5Qd2dzWCRC>z`VsQjOo~s>UR}uO21G3b~5>_sl;f1pL3yp6Y(*2 zTg|QPYVFdf4n2i1ryt-~R&&EyEH~GIaAZa|e{p<ldYm><(Ym$Sy#1kbWFdS!sl4#8 zg+-&46R)?p=v<IrxKAkB`h2<TL4-|Z@SI~R;xX*W)A-68l_8JKw;U~tw3<);5q%L& zO+WVhmV94&T?E^GFg?51+bpQUzhTmQhVhm~3Z0o+9h<ZCwR#@S#fJ;<<Zb)oT##J| z)~QSg4M#(dpu=3@PP3E!chc@*v$C?VU<{A|;Ea$C)Mvphc3Q&ID5^bSMg}7&YYEw! z+G=rs{cXF{PQvQnc;JJIsEn$r4gNJx`JpL<IafAY`AhBA`O0bGjYCz{Rlhy-wHk~D ztSrl;%8Mf2s{-cqz(t1-!B^mBiO9Ppot??{A(!2P0&-5fl5P>dx>DZULg*TK_Nrt5 z-2iOB@sKY=Jc0s3a*{6G2s_h?5P1!wrHzP^j*5=&P&pEke^pz|yOz9TpDUboGQjBx zMo!1otB@1eyV;Rc&(=*V+v==K^@N)awupf0xSm8APIR0a))g^~LD(V`iz%%B9lV<9 zNW9qx+^!S-`8sx=M=9LFn)pSWRENVZslD!B8wv}&N}w0~Q)Iq<_h*6eL%R>T<xbtB zHVKX_vJbiD$PIhPc3|ksSjnS-lh?8Q_gnrdZaWp#?-x#cg*}W&rboNyF#et@q1F6p z9T*>0alj*U0b~~`wx_Vx`_n~Y1o};*=weXmz#wPa!-WHU)K7MW;+k{KB^hrTOISzk zQem*}7uv?l*3EgQg4t*IhG!(iW+b}Drze^M=7@AaA{-nMNQY2Iq`R||yR-9g<Y{*# t(zVw9;QxR-DG5oKoc{o%+b7`Tw>#41KY&_u`GpC9`TGX?bfIFt{})E(L^%Ke literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png new file mode 100644 index 0000000000000000000000000000000000000000..76c546a4dadd7fdae310dafcec2ecdef9649d4c5 GIT binary patch literal 1377 zcmV-n1)lneP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006>P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZJydFPPaY zjqWG6vC4&kzm|uj!nL^a^ZV4*@~N!lj*;EL!|c+nY?{_9i1sFWzH5(?-O$nT?A*cg z?Z)orvhC!s?BcKR=fQ#6N$usa=Gm3y)|2GZkm}s3cd&fiz>e(VuH@B`<I<1f&W!2U zr|sXy;?RxZ&5Pj5iRaa&`u6Vc<G$$Fr{~tC?A^KS-n!+`q2$h=>)E#4zJS}je%iZz z<IA4fyMEfbeQRKz9{>OV0d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U00K`* zL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U6fJ!G0)j%qd?aZR z5fu}c7>rs-_lqPS2uKb<h(XgGuGEK33lp=Hw2Um1oV<df5)(cx$|@?VY7i|P>Kd9_ zOxilSdivP3!2P0PU|<N*L%<e9h$*WW0rh~yjKRJz!Ik=uLrmGoKm|mbnweWzTAAVs zOBC;`SVOd!+t}LKo8n3rs9GE#S{$96U0jLO;s(*;?&0a>jav({i+z0kltEhjT>}Dx zaQX!$jRpIKgaY-1nSww#aj8!^Gy>=})5xgkm{?PyQeSXrL>$l-)A)qMq-30aK}mc* zDRE%Gq^6~3Wa89<QYfipK|(A$CpRx2w-)50Po)5&rLZW!xCEzPP;Ds%YatL~kR)gf z39qtp6+&Uk08WDD=4PfK4Ju{j6{^H&F|VwwG&cpi3aCSkSS=P1TU3bB0n$=sQ*DYQ zQd3)3UtibI*wozI)Y6L8FP3fY?MPZWI=i}idV2f%Crq3;Y4Vh*m|7qK8ivp@ZTgHE zGiJ`3J!e`6kUM)8rXJI|^X4yD2)CuC6QpC&l-Udnb2@84dZu8w&2;gSrOTGXwbXV2 zb<9{X8N^;$3nC}CU}#yjdd=E(a4mJ+AT3RkK<xE(AaYU@hL*q$8#ir+YpL%6X=$Da zVsEJjkrSISv~1nBJ$na9TF^p_D2MG#-nDxVY2M$pci;X4qy_TsgNF_wv=9}Q2M(cV zAtJ$;mK->6poFAkiJr!&3jm~}-@X0I9(w=)03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfh#BXQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png new file mode 100644 index 0000000000000000000000000000000000000000..ba24ed16aeb0d93bd133902b0b2218e674f84528 GIT binary patch literal 1402 zcmV-=1%>*FP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006^P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YN)&~ znAt0h?kBgg%7uZymWQOmwYc*0`_$F)sjTIWk=?<=?9#1ln$|0b_9lA1YmbuM(9!Yi z+`;qh#_r~_?c}iR;;-=M!GYRI?d7rN*_GwiljPHo>fEY#uzcLWj_l&D<kgYm(vRZK zjOo~??cc`Y(2e2Ei{Q$M=hdb9_U`ZFzUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyHkc~n00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~ z0%b`=K~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4 zBxw;56%&^jj9OrRk(88VkYoTMLO_ZS1f)P}iPb`eEpWepZ2==#y2F+Fuz8<}Sz1O` zj!9lYQAwEzpB5EWRW)^p77h(fEo~+pT|IpRY+B&4uWD#$1kppl7I=sOZ7~Mw0g0J_ zePN0#^&zJ*6=OqH5N&2|VQFP;hAZ`<cwf~9qQ%12&fdWcSGqve;t0{=<m}?=Mx+*Z zh!zh|FK-{*T994r>*ucm(h}en7!-`tFNhEWf)M}EFrc1rGZ2VCmcb2F!XklAGmDCj ziH$QOD!+z=MaBbdF-u5HN>0J)7nH>3n;H-HOImtHW)@B@D20-0HYCJya`W;FaBD#> z`cw-cT8fGbN=kA11=W@^uoeO#21$Y@knk$6P$d+m4B#YaVPS3t(x6&iQK?3Z7K^H? zDho5PtAIMxiPd5Wu|<_A9Uv{$wl!u*BDHn(4Gr~;P0cMW&8=-%{bJSb(Sf9;v#YzO zx3{l<!o*3FCQq3<4O0swK*JF_rq7r;bLOnsbLLL(1ajxh#?)grZ~lUXi{Q4@c7b#( zo;rttVQyC~NY7LZx0x+jx@`FhxR$zZppKa<r-0b2>Oka_Rtznx*Q{N)9<HUn2c)HW zGKjsQ9z;%V#?TV9ant54a4ikJAT2GEK<upzAaYU*hL&yHcjW9ONefzt5#_L5DZBUV zCC&T0_w7G$khDPFbLjA4gchQr^59_<Ekq<3v(keH50;XYEYZ^#bpZet8{@o}32r3- z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f<D*lWB>pF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png new file mode 100644 index 0000000000000000000000000000000000000000..fb536b11b68fca6c2feda14a8011003678204d62 GIT binary patch literal 1389 zcmV-z1(N!SP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006~P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZLlAj_u#Z z`u6U(vC4OVr-z4&!nL^a^ZV4*@~N!lj*;EL!|c+nZ0y{@kCNSe%Uhb(E6~yL^X<m& z=CbYNu<YWm@aMsZ_9pG+vF6#8<<^tr(~#=is&%M_sJt)i;;!V?k>k>j;?9ie*r$Ha zR+!l<;?RxZ&5Pj5iRaa&h3hnp?kDf#zUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyg@M18hosTq4gLTC00DGTPE!Ct=GbNc000SaNLh0L002k;002k; zM#*bF0006~Nkl<ZNXKJfAR90;fdC^ZT9}wwSlQT_NYcW=$;Hh>nikS+;RXAJmlQ30 z`~reP!h9rY5fK#=ml%v%NcW2*9|%YeK!`!p9j?@eO$!sVl(dX2lbpPQq7oB6Ey^k? zs%j7|9O@dHT1?tHx_bK9w7~tMVqjnh(L=x%M2IP?7y<Qw#EikdFu|4jkV8z_$Up@| zo0^$hSX!Cl3QH94t5`#{nA_Oe*_+}@7pPhsAX*%qoLyXr)Zzxw;_l(;<&9elvWtCu z{ggpk{9OYAgK+u<C5;99g@gk2gqeasIB}^@IWz+3G}Fka=$KejqEcUQXha;)7Ss5I z#H3`LenClmJ}Gfvzoe$6XJq2kf>J1{WI;kKJ0~|UAGa3dqEDp&qNT7XzqkaaUr=o+ z1#2M?Vvr<g3<<BYauq^h$^cG+=H_OmAPp*I<rS*LXfdy>tTZ<Ty9%g7jaV%f5L;A; z(gD&^Wm9d6BvMmbS6^S((Ad=6+|<&F)i0K9?(IlgIy$?$dwP2N`X@}BIBD{fshC<I z0UCzTF>N}KoH}FXtZ5xU#_SoGdQ9icoi~30+?JY7kdD?VGZ!wL)ma15GX=wKri&IY zS-K3arM3%1wk%%=1S@Jm?8z+{T2`)Fy=E<3OI<gJY+47>vc3+)p45b)C2+&WO`G9b z>U%(B^A?bnt@R-G#AXaF+qUn>-bs=cv=Af8VY`xd@7YV5_jm8xf8Zc#fxPF?;ll_m zL`CJn!zfx{3FgRAoC(IX<lw=BB_t(F^fX3Y007N*+;lfqX*B=<03~!qSaf7zbY(hY za%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0 vW_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfuI2JN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0018157f64a5ae601a2db08fb1e4a553385c33b9 GIT binary patch literal 1417 zcmV;41$O$0P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700072P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YTUq% z?cc`w_U^Z_%6EXLhlh*8wYc*0`_$F)sjTIWk=?<=?9#1l?A*bRlHGmFTbkA@(9!Yp z?Z)orvhC!s?BcKR=fQ~fChg_1=Gm3y)|2GZkm}s3b*P4@yf5tHuH@B`<I<1f&W!2U zr+&{?nAt1h(2e2Ei{Q$M=hdZ!>okq-C-39F=-8*{)}`#-x$NG$<<Ozz&Y$bqw%ope z+q{0-yM5!!p4z*9+PZy(fxniAqyuE0`2YX_0d!JMQvg8b*k%9#010qNS#tmY07w7; z07w8v$!k6U00L`CL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U z6fJ!G0)j%qd?aZR5fu}c7>rtAevy=vWRPS4Awock4+Nw@YKhfChAnWvfNcRISh~ZN z`mlMQiCJ1kR*p$tK~YJW37-}fRaG^0h!zeFO)YIE9bG+r18iF0v9D@qXavziz!rFj z0c|k`>H&$FfPG<#EA=6#F%@G&RS<1vZeeL<ZH6oLp?F`_2BO8n*3RC+3|G29)#3=z z;^ge&>PDm%cZe1bPcLsD+**)b?Ca;R0@4!T78n$a(=Uh+1A-9$&@iB$a5E5yK$gJ` zRKg;GPBV*&j){#kBPzd!ghj>!Z81woOiE6{=@*p5=bIW2_DfoNMrIaHEhvSOYBnUq za&q(X3vg>eF8WjpAzF%x3rb3H`UTaNGO!i`AqGi;CXnzduTUivrVQXDXklS)2GXEf zUQww=j24TkswxXJu&aPN)QQz%39&_$C><az)wVTeNFud$^$iX6jZMuhEzPZMSp8zv z?$LpyrL(KMr?<DSf5OB`lO|7@It^0`BtXLvI;PJ6lGA3+nmxS}$e1$|Q;*r)dGi-6 zgxgZv1=7(rb=IOqv%6|RdZuEy&1~_KrOTGXwbXTk$kr8$fM8`Eh&`nhL(8hwYu2uV zYpL%6k<IHtS~k>!*pr(vv;=M3w0R3$OG7V+Y}pFZvaJEcp45V&W&4huIlD;Gf)-*# zIc#^zp1u39dcPZ&_xJ2SaPSamfxP$dks}B#L`CJHBPd#63FhcAoC(IP^w6P0r6eUw z^fX3Y000U{;7!~3Lt6j<03~!qSaf7zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4Fh zG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bN XH99ab%9mBF00000NkvXXu0mjfCZzUl literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..3a78fa6a1d35d8b2666ee3ffa5583db9662a67e4 GIT binary patch literal 1490 zcmV;@1ugoCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70007fP)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j_U_>5)wA5djnuJo)yKTSzu&2=<&>D;#mDaG==ksIwesx6?A^lL!H?z8tMcd6 z`}p$9v%Rr~oVtpQ(zUVm_Wa-A^}oUFs;%YG((&EGk@4lw_t?(XP%76v4Bcit{POSI z-Sn%j=JV~w?&h-X<go1Gukh!=<GQ)mQY+$cP1;Eu-)lwf<+0}3mF3ox<kOJq+^Wd6 z(8ivy+*T~?;;!V?k>k>j;?9ie*r(rPJ=a7P;?RxZ&5Pj5iRaa&@3EfMdPDEyzUbJe z=hmg{-MRG3zUrWd?4*wR<=^byy5-QJ<j$Y#*|yxifZM!&+Pi(@%bwc1e%iWy%Ued< zo^8}&Lerv`vZEDM00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~0*y&T zK~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4Bxw;5 z6%&^jj9N(dizFWiNDe@VLDL<s)Q3$A6SI`Gj4YF!yn><<6Fx1<Dk`dK5G@?)8k$;6 z+B&*=`q;F<{i0%EU<lDez!pS^DXSO(^?<~T!M-rTmHLoFOxegl1w@;gnOj&|nc@md z6z{88L$sLN*xK2f;z}2&S{xu+9G#q9T#3};2GQc~;pyd#TMM#_eSH0tL0bG>0|J9^ z`UNG81^b1B0`-KMf<QQNsZTjH0_Zf;$f)R;SW}`>UvOwd9MBfi_=LoyWSo9MNqjyj zabUlsrln_O;?#mtD5+#YLM%HcH!mNz7UZH&r2wL(uqeN{1gBq6Z7Bt7ArNAaBxno? zud;F#LSf1PPJ-s<W~LwwDrMyrs>En9udJ*zHwC*2s6&ldEfx@4REW|6(o$tpZHgpP zQ(ISGU)Rvs)ZE<E(u&nDmTm6sNLo5NySjUNdi(k(Oq@7r@|3BVS|9-$hR`u>Is?Ou znX`ak_8bO=x$`jfn9g6YaM5D8Ej67$9SlomEnT*J)~ppk=G-Y5ZZloEYW146a4of6 zAadP$28KBsX3YYzC%0f|*|=%*maT9tb=@GcX%djwHfuYGJ*f#pOW=;3yLQ91)c1hM z=7|gpduGkr3t~@f#?Z2F|AFj-7+MZ(n>FijJ$5Z<AqI2Uky*2jcGux>*s<i}Cr+Yy zzhyE|3qw~e4(}g7b^6R%v_Nj1GM9m2dS?xeKt6Hq{CR{HNK`URy)bLm#SR7>QF-<} ziWX>sxio9mWn2lywB+pBvn3=YOY}5GT>t<le%ij3CAg3P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f^-`z-2eap literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7764b74f5e5e5af1a205b2ecee9ed184727e1fe0 GIT binary patch literal 498 zcmV<O0S*3%P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70001NP)t-s|NsAV zbaXa|!Dg1x!H+h2o~cd1>4~}9VaDrk&F*&1?7h9crNQLey@{>X>89TD^V}-D-R=M0 zDZt<E!r<=3;qS-e@W|uv%H#0M<nj6DU(Mz6|K?xO=kn9&^VI3|*6H>3>xcgAhT-q` z!N@d;00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0Ut?3K~zY`?bO>2 zf-npQ;7O;V0?Nb_&J(=<J35L^UDqjzCdSySWyu#<`)@-0>*s42VGTQwXf%l9@iclL zNdOXeuiySypCM4!;O@y&X{wSOIUXq~XQs-}6QvYS4hKrA@L4=0l~^f9_IpA^Zz9B` z$BhkkJMf8s@sL*VhLWpb4Q#i-2+rIQ+9-eP?noQ0lYBNH*ld8!i7ZVDly=E_-I=Ub z0iwNRxdislWu;A#vn&>!J9Z<@Ox#J(okv2`=*=e-1+Z!K=krEr8ku~;d=B=YX>j2X z3`^5Z>~y=h^w%!z!<XmH<A-BxricT_g}zMDF0MB}&$8Uyetc9c(E*Y`k!1ybMZHLj oF&RsOM{v$!pYbjo``5SC8S!5pi4Z+;&j0`b07*qoM6N<$g5#I=_5c6? literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..d44eff429fa9a3409776ea88a11421582f6f4598 GIT binary patch literal 1298 zcmV+t1?~EYP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001q zx!X2~!Eep(M7`;C&hL59?^VL-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUOPl=ya2odY-AJ!Q^I^(ZP>4@#=@|<6!gf$nfm8 z@9DMj?Zxiqv+?W1?BlTT>B8af_vhLx>g1j3<DBW>n(yed=-!#<+?Va;vF6#7<<^tz z;H}o__3YxW=GvC*;jZM>lI!2C?dG!U-mLKEz|`sV%c5A@y@~4Gs_*2!)9CZ$)RE)T zkK)jc>DsB$=kny!kmAma@8e(T+p6Kris{*?_Uni3;k?b|^7G_h=+~#{*QV{@yYAa6 z^V}-n$%)^{h~LMD=G3Ii<nj6DU*5)s%H#0o)urasqsZg%{_KYD<-qLSy2s=2#o_P& z=3ngIy5`cN=Fy_&(V^_zxc}ZM-o%96!-L$xg5}Vm+`fRq;O^wkpX=JUz~AoV&7SJn zw!Gc#+Pi+^%$}{*>Ep|u5BdaA00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0?A24K~zY`?UdPD5>Xh3ZKAN;Q_C#*KwubLStTT}1_fLIkws7h8A(MzWmN>> zU-!(C!g1n>o1QNGE)F-m&yV-_9Zp~0%lzwkMX>Y7Qw$+qOC*vv#9OIU+E4Vqdp|Hp z3=Rzsj}RlHV`Co(QA9F6K0ZNAOioUIBtA_|O$`u3pQX}aVsv_XV2tRNGV%8*U%21Q zpI@J!9p9ai$!5?8$Q25O9A=eD<t)sqR4O&7Ns`onhN37fbRe?1IT?#6=I7@Xpj=p3 zRDo(~X=xcqonCJM%4js1F=S<>16kw|9SNjfucyFbG<8Q*i!8FN(;>v5|7N7XYFb^j zi6er`Z;S7og+&Wmv(4_nkhL`y`2p<k=g;S-7$T&omq}6$8iRq-fYxd@JHSEHv=d8N zUvG1Hvaqlg8+M>wZnp<RHaFW4Qm5mKHCn;Ey0JwA?RIZ>L3V^<DXv)CmdizhcYE9C z7f0lZot<3~3#Z5L4`9gNUeAs32*`uMAWESuRxLPecC-tp*W+<QAQTEmL{lKRzaI@^ z7CvMViX9xrG34k-K%&tED%OOq2kmmXz2Ncrd?5%Q942w(_?SncEW#FR7mD@!VzDr! zlF1~4AtxssvYSXG(yRsji?awIi*PCekvPMgV#wK9&yAg*b1CUWCX;4&;YGXf`$GYU zq~h@lIL+qrmmrE{uCA^!xWzRCxk9m6>W1*wBNU4rq#&NWE@UBJES7PkQfWgTi$%L& zt_y`cl#1nYRUAoYSeFiqTrPhDH>GOz219Oddv1(Jgp@!yg?4elFxgYMER{+qrCO`q zwWpwmuU=;#Kf#5+9!!C=D6<x|Mx$}xj>y*P&1N0_`voL*$X<^uSL_qg>P)FLo0X@O zINC)Pazz%YmdlMA+~Wvh&>fq3bh%)%n8jVI)w=6!OnAn7Y3ybGuXzBr6b33x=w6}# z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f@j>KSpWb4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_insert.png b/web/pgadmin/misc/static/explain/img/ex_insert.png new file mode 100644 index 0000000000000000000000000000000000000000..862d837277c99e17d2b66232de79fce010752e7c GIT binary patch literal 1065 zcmV+^1lIeBP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003yP)t-sBmgK| zTU$1W!3nA2a+aZzl9IuXHmaF8ou4@}wdHlD$3eX4%c58k;}QztMoPfx$EtN*#Oh<l z>TAd7XvplT#d&Va>__Y%vc!A9!GLwm?AyJ6+r5e0zJT1nfP2yJ+`)o`(eB;DgM`!Y z-o%97#f9F+hK$ti-^YjF$cT~E?%>IZ;mnGc+417ejN;IZ<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp;FQ>)N;I-kIv%s_fjj>EN2{-mL81y6fMq?B2TU;H~Q8obBJc?BTBM;JfPNo$TVT z?cu!a<FM`JvG3%*?dG!X=CkkR!0_h4@94Ad>9z3a!tm+B@a(qn>%{Wy#q;gP^YF+M z!Lnrl0004WQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkQhe<?1R7l6|m0NSt zP!vXK&`lBB2CJaOTA)a|q(Gri2tkO1TjWv@3IQV^xBmZM;7QKm5)32GIHM2U59@)+ zO7{1iGlRkKH2+{;P|ED2o<i9y7RwoRabmSzQkSo7wrlG8!sWW5Zmt4>Pn51=F&d2) z>IBhBy)v84HtG!NF6!#^)E1!r(pR3TJMW~P0*}+_^l{1Ycsz%>EXy;PNs=@H{0soS zsZ1XpT4Ta-wOSp4TqzX#AZ4@ZCSYUngQhh~OI2D}smLG~3Iz$e+4NHRx>yYJuvW$` z^<kBxN(CwX!so06?Q|;DAWA+@Hy5zZqVB&+@l8$9oxr5os0~RL2mO(muAG;k%==v= z?{&03tR0w-WO+_F>-VJ@Oxn%n5Qd^C4wf(0IAs5IimsC4t_ET>94@Z+-*8Z+6;vrE zDmL4OX6o)%1Th>A6*p>99W@-O6jM@*ZQMqqB9uZQMgW7>p*i#m+5guRgQ6hxVDr$y zp&Tmg*VxiQ7K(#Tq1&Di4jVOe7K2i;IDj6{=Q^OhkHF`j9~j8~+7t{*!3X_54z}(v zzyVU)=`^|+m|`><E<urD7#?zdpLbg!qEcy%5Em;j!C($DUayzcSJ3|AcS0pa52eUu zI?&-*wyvxEL1XK$h+=6#I1mKB2b~PZ-9tT@h=0*v4DY{{!oxzs?R3WU6?`!;`C!nW z0nY1jCn4^1p6^g_rK@7mS+E|rI}S1D`FTWN!TW1cBogs5lw*-d`L~U|Gby8??pJ!b z3_1msrXytzkCh?RRq(}7X*#mo?MOj9Ce&3jKILMl+*jeyDI_uXRqokjvW~fDmd(cA j94hm6lTUy1|Lgn&xg@`Em^A9100000NkvXXu0mjfS$;eB literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_join.png b/web/pgadmin/misc/static/explain/img/ex_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c391233c449bdc5a0d52d50f522bd3e35c649c36 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_7<@W^2*R&GEgz?Z3h8!ou#;)brTc^v=)n(b4kM)b!xs_i~n@ zTZg#3z3iu{=c=sduCM9E#_!9_@xH(9#m4Z~*7U)THuUky@a(t1!S2S#@6FEg-rn}> z=AWyq=(DuyyuIzz)bo;+(T1sHQjHmZrCYPXrlG`Mg|bG+s&$Tqt8$|?qQ_wH?6#)N zW$Wdh>g1j8>9p_bw(sb(^6bTgsA6`iJD#<NuG(>Uu0Heb#_r~_?d7rT;;-=M!L{Ui z=GvC!*OTPakm}s3d$U61)sf@UkK)gb>DZ@@!Bgwrtm4p);mwQS%8BRHr0(Lq=+~y~ z-MP8zf4c61<<X(!&Y$Yow(R4uyzqqFzJS}je%iWy<IA4v<DBW?o0iO7=--*_;H~M} zsqpE-@8-bX#f9C$g5=GfwL|Xa00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0r^QpK~zY`?UUJC(?Ar(V^BbpRmDM2l-2b%E>$$61+gq;DJ?Apx>_)8HEF30 z1qv<yI!QY65i<h=Jn+JOn3sINdveZqt{_~`MdpTR4te<yvEk;e#wM}(cFUc+BHuEx zwXMCQQ|!8T|3SCNw~VdAT=visCNG}~>Uq@L_ZU6tfBI|y*^ohN&5&~$8Xg&a{sO&x z)%W_19RZglNiNj$_TBprh!c_AZnuPnKYkkfd})N~g^7GY=8#tqWQ@OlJIjk*1$#W> zgqZ+yzW-as^djR)gE?nn@}vi!H!=L<1mfjN3{M>+(=)SYCw3BX`FwNp6fe$M7+;i6 zP0Ts|#ifABKyWz}Ug1&^<UqvyH3+S)tw$+doagEfL}HdoIG#wRD2Vfr7JgcU0O^g* zUkVLzoGXry#4@R@lB0NWs^H)F^p4ffmArN24^hdfs+Omy80GW&f-oN{gjc}IE4D=t zwfMKBQ@nt8X1hFR1{zO;+2q*P4r#JhD$x<&c6oOh3TyF16wJRei2A*N&O&C(yQ>A* zTTdh_V86<|uIp4UMlA~aa1gDeGGHqKGqL&y^4bu#%6@n+eE^xPqU7u<Y%fNWHY$*+ zR%<FRl1?Nyv!GOKHH{aECXMoeS}PV0|3jEwtnxul(+=~OPV9QFW{v><WVgBso0Wk8 z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f?exDGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_limit.png b/web/pgadmin/misc/static/explain/img/ex_limit.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3efd59d70436349e5413f8c5d2673200cd74f0 GIT binary patch literal 1237 zcmV;`1S<Q9P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(M7`;C&hL59?^MF-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUNiI=UKt$YscuhV`Hfo7w~d&?QwDGaB$~uaOH1r z;cjl-ZEe|XY}0FNhN)yyjTym@HuUkx@a(tm>$dan$M5O1^X<m+?8WZpv+d@x?d7rY z>%{Ehuk7Kj?BK2N=)$7LVC&_c>f@a6>b2?Mn&;e?=i8R-<FMt|ljYTt>))-W%w_1_ zndaG*<kXSm(~#=js_*Et=-rs+*p%bakE+va@8-bo<iD=jaL1~3vEFs<<gn}Btm)gT z>Ds97;k~rudA8?#xaxo6&Wz#Ai|N>>x$A)A(2n5BiRjm+=hmj@)urv<yUl57?A^NN z(xc|lqU_wb-^hpG#)jt9q}{@U-NAz8(4pSMh1|e_-NS_2zJTP;pYP?s>)N;G)1&6m zq2$e;<IJAw*|yrdedEiX37wJX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*pySK~zY`?UU_O5>XV!X``@E)R3}Nf|O*B$m)u`ByS4@xQIz9FPadbCWy#_ z5QxIR-d(t0;9^epp=NwO+}WKuzd83g&$%MegZ^zjB6tlvg%IMgSS)@*Je5c!L&VUt z=h9(fctj=}B}T`_$6pYFh*&O{i-`$^Lh+J#H90vcB}QJqnUWD>)6>#%;<hdmlBqj% znNi+NGuMdnZJ$&sm0G1%znh(%otvA}Xf*GU=I537>Y^pJA`vX;bh-upT-1Y}qNpWU zrdJHBuxd1!Er6>!B0rD_(XFkm>CkDl+JLg#?KIF1r;`Dr%kB06uIeHmuaQNo)k-16 z>!rcq^!bcncKg>^z*Rzst%U@<-VFmVK3~uTX8-!;P2>~V_R@9{;9VHHF1A>f4FRs| zBA?OE7vMGU#8sVnk=rDx1^uFp(!)}Krk7!LhhZ#WF?+&W5Q;>jF~C)w9^1QnUrFAD zodO!W2)fMJMPxr7PXMm!blKhehPqHzyFCE(hQql7Owi>vLwGZpj6gIVPo)7@b#KOh z^I4$5t~i`N223uuKMZVge?JO|R4R1<xT-gO?1Jfc5lbH&9`&dHC!2h8X_3C)(ET>K zCEkTm$i;CclRW{Uhm5oEtZyb+ez5U09OO<<^N=|!6gXkT=yIVYXK@xOl*Qp`v6z8u zp;Q`xnA|;C<PITUES_h9E0xL>VZ`DIvp*md{nbSlxu|lLN>vc~?IsI!LGL0Gf><J* zK7ylszIF^J7aUiGYNdX8C48}77w26U^+u!76h_)hp3ddaU~A`Rg$v-yWrSP~M%qh` zvMAR0EYM&p<#MBb8`9%~Yq_ZNF0Pu*=GEVt*n|Fa{RGa817HRj*Pj3Y03~!qSaf7z zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6W zZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjf-+GHC literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_lock_rows.png b/web/pgadmin/misc/static/explain/img/ex_lock_rows.png new file mode 100644 index 0000000000000000000000000000000000000000..41c1148bb185c87898b3fddaa76be36a15703336 GIT binary patch literal 1520 zcmV<M1rPd(P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700078P)t-s1prKL zYin<9ZE<dHb#ijIWKo23T)1UXxMxwgX;FK4c)Ds)x@%E3h{3vUQGR@Ux^Yo}etx`j zQG<Yhyme89f`YwxQHX|yzI;)Nh={*{QH+X;38~`0f>Di(jE;<qz=Tnbj*fDcp^%S{ zz=%=8h*6S~l9Q8@!H+hYm3+dEQI(aIm6n#4mzS5An8cD%#F$YswdI<go|~SYb*9Ih zp`pT_QO2H8o};6lq@>5AQ9-=u%c5Axr%}nMQA)t+%BxY=s7}hQQOB=S%&$?Wv9Zju zQmC`DUBv4BtpTdFwW_wZW5(*uwpDA#=xE67&bnBwy1LG~S+BgjZp-YjzP@$M?Ap72 zw8FyMy@}(!bKJgw|GhAK(eJjz#N5GxgwgKZ!-Is=@ZQ9P-o}QE)b8KMhu_GEk=5?t z$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+m zlIGK+<<^tt)THOtrLN%f=Gm0!*QV&#r{>z0>Dj2~+?VOvsp{Fb>D#L7+PCQ5nd;rD z?A*BN;F{~+tn%Ha?A^NS->vfAr|jOk^xmoL;H~Q8ob=zR?BTBM;JfPNo$TVT?cu!i z;i~N8u=L}t?d7rb<gf4KzU}6+?&h=a<-qpkvhe1>`Q@?i=(G0cv-an-@9DMq=d<wX z!uaU6@a(qs>bm&qxbf@6{pz;(?7H&p#rf^N`R>2@?#1))$p7!Z`SHN{@xlA?!~gNV z|MAlO^v(bC)c^F+|MtiK_R0VD+W+?3|M<<SyU{8D0004WQchC<K<3zH00009a7bBm z000XU000XU0RWnu7ytkRE=fc|R7l6|lj&CyQ5eRxeH+_N%WSus*<!m=*`Bu8B8iHI zC~mlcpojwm1gMN_hN04AG^HkyMp;_fzWiC;xpx#ij-Jk`bLxZdhi7KancsQe=eh3< z3Yw{ZPzMOMrc^$J5DEl>R3a-OF)@e8xgr!66UABC*%d@ZUSZ)af)^1)L_`RP1gMF` zrP$b5A(0C4Y$7i?Sy)K?L6_Y-qqanb<M+*I<|&mUcAZbVnRe~SO7sCn1_lO3#?<5S z41pnrVSK<x)3g_0A|~ZR%)0Q%xVS|K8R+b6_i*ZIY;5cUjNNMO2DH(rb8yJniyPR- z(tX=Gq#Ysc7_l>ev0AM(=rZcYkf@Xxj4t0ln?*eB=x3yTb~{A6t+$OdaO!GmS~0Te z24{TE!C>SC%|Gtq5pvPx1ztyMQx8I}?^v_?^qCXK;t$OVo);YybP}+Yfi!)xvdGo< zqo2Nf{PF$s@L+%cR@fzzEilx_FhjuC-A(&|*XeNdfF6pX+^Eatcca5>4G#A9K3UHq zNl8hW0WP{&7u8LGQYjQRgq(YWkWm(S7&eYDb~_H%=md_M>PiYw3PmYKPQCUc4?_J2 z3YJE}wpOZC6sRjLm0J*U{FNWMzhd0WWEXCm#o|Ip{0l#FH{`bxJN%qQMiFvnG3?@_ zyPRH5ds>^|S-9(LHaBpY&8802W$)8xFF$<!`R#4*z2@cx5W(|LbRmZ>%tZzHdW7tW z-nMaVSm>%{Axjp{p9>MEP6rnQE2UB?>VQoymz#m9AYY~jd{+!b+Qcai)*>$|G6923 zCL{R~I6w86Q`UtGx-c0!K!=_rTX>P90f}WyPLIC}Mb){v)4|$d(Cgbki&j(Bz&{wC zAMXHG=pvT{8mUC0=11^i1R{D_u2c)EBogry2#z!mA#<hDDxj8##Y%p}ZLyeL6TGx& zG*$JWUaeHt|Fy(iCIdVLtZgKzZ2=8xwHkI&mY3J^4~7>5D=9@T#H@>Qkw{d=j~MdV z#lWgX!TOOBenbyXLCdK|!XiqsSX2(mrbgOGEu0@~po`j)l9JkK5=)=%R?gJ_Sib;} WuicyymX%Qe0000<MNUMnLSTYGrAb2o literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_materialize.png b/web/pgadmin/misc/static/explain/img/ex_materialize.png new file mode 100644 index 0000000000000000000000000000000000000000..c3bd0bb90dd2ef1cc1baf7f932817d1b6bdf463b GIT binary patch literal 1221 zcmV;$1UmbPP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001^ zyUc^E$aSX2Hi*HV&EAa1-IK}Ps?y-H)ZnGh-mTK#zS!b$%<V(H=}o`rQ^M+n)bNzp z@OsYdhtuw@-}7s{*>k?y5Ub*3#pqna>5|p&pRKHao1$`-p~$a;;^52R-owF<HuUhw z@a(tV+qd1?w&2~u>*k;8<eu;8wd&)Y-PyJ2;hXR1v*6sp^6kaUy`#sfb>G{;;oZva z=CbkX#N5}k+|{$*+Q8@Bm*&}&?BlTA*tOf#vFYHN=--*_;H}=+zU0-B;M>TCsbo@( z8Sv)7tJG}W*1h1`$FJLRv*CB}=)&sVtLfaT?&7`L(XZLhuG!A5qQzgO%Ve<JbGPSw zxa)u8(U0QJjOp2^+S0Jx)VsRuf#J-G=+~#%%&gqgy5P!*=hmj**v0JKy4%va+tIk@ z)THLqqu0r)-^hpF#f9C$g67eo*vzZg%d6JMsM^oB<j$bnzJT7<!|U0$+RnGy&9~&u zp5x4(<IA4a#irW2ecQc%&=gc%00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0(?nCK~zY`?b6p*8bK5XU_ww#jGAI1rVXt0A|?yUN>Pg78bgs7LkqpPC|yAQ z^~}hc;|y@}z&Sa2@IKs^*>CRt?k<n_Q2(eN@lkOdJ9#WX#r69K{Ds9u;S&GJ)1~ES ze2fTIR@a`t5WIY~zW!Q(k;OL~8$t+$3(Evq6^TTff|a$mo9_g3PI><U71uHH@iqn5 z?;ilML?RJ$9V671R4U!#Iz}WinM{JZTtN`2QmK@pu2N4Wa``NxQfX!ot#$^{Xmr~+ z;j$<c`Wac&>g^qjd;+Mrj*-t4Dy|b#6bd*+Pt%5pDQfi=wPQ3IcZn=8g&xp*CKE$u z(db|b<Nm(cf)j<-YNY{fGTBI?)*T!gAu*fn1hHE8Xuz0kHU~)#4k59a%}#=dX_Ugi zI2^7!a^yZjWSnBxZnt~>x-s`LGP5^kU>L>)TrA6;0C@jxeL01O+O=3LUn!5*>+|C; z#@J8_HgFbX0nh#I{QUU%`{~6GH;+r<4TZxIl0>5{V9$cV*q<pEKhYGs)9Lh5zHmIA zz=<Oo2tX1{CR2Cu-AEu33i+r=Je|(qWSk-!OQo{J#ynmhOyN&tGP$|`u@jb!WkEKd zFJy^N>4`)VekxZimGCKCihQ|TE)WE!sAQ;OwN|U+B$oVjnFob(`Km#XM7mNfQuSJ` z*2GEb@)F)(xVoAknM$=<f~3_V2ujfg?M9=~CJ0PX&rzLbv)P$@W7$Fh-rw$adlOUY zb$Ea0x<A0Da4EXO;jl-LdJCoK-`v~`aMFOJ3wl#Xvo#uBQ-i4lK0K9-M)2V&WSpYi z>rG_o^ihh=U@(|_V-NMe)o+jt(ePu5AK?H103~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfVJ3t* literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge.png b/web/pgadmin/misc/static/explain/img/ex_merge.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd8299fdcb72604d0c97816d38ee25ec51699ff GIT binary patch literal 1127 zcmV-t1ep7YP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001z zmC<Hv(ap~CyuIwd!0pk|^3&Aw$H?!;$neU_@!Q+=*4Opn;rFJf=Bcaa!NTsv#qYJY z>$$q@!^H2!#_)!zWKxY8p~PNwrpGpj!Eep(LA>Zn!0CI@?}XFvW5()e$n0**?3dZ` zpxg0;(e8}Y?vd5*uHf?tsp4J4>N2(Eb<ON+$LOQSVRDwC!H+ic@W}A&w(se*^X<m& z=CbYOvGMD~>g1j2;F{;$m*?A-?BlSe%w_81oao+}=Gm3(;;-o4nC97(<=2z!;H{?6 zXYAmv@aV$Fs&%W?Z0p~x>fEaD<-p_8kK@pe>DsAbl`meHCBewL<kgaJokg0;U3jiO zp0$U%?SbUekm1dYi>qviyiJ|ZV|uVayzqqY<iF|Ir|#mtzsI+$-f_6=fAHqO=+~#` z)}`&=yWz}=;K+#I$A{+Bq~67a=F_9#$%)>?h26u0=Fy_;-MZ$|qU_wb=Fy?$&!Owu zx7@#g+r59}&Y<1Fg5%7dI?;o_00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0v<_3K~zY`?bGX5(r_3DaGDn~EzQc+f-=ht?ef4F_ZT1uwF%R(Lb^=WWfKN0 zFq@$K>;1-ob697`-_$p~@OkmP`<&<Z{qD@+xE#k7!Wh%W5n^n7Vq%hTUY)u&O-wtT zGuH_$8NV?*J4f7{pT9LmOy0gTHS@oavu8O+V;7hOa^b9myh~n)+@p*!Z5*NQyWH*v z)WgL`OOL51%THIHQCQ;gcsy=ub#2Y{oLXL8e6fNj_O84fA+P%HH*FjNug~Z6f|sUg zKlm9Y5Ckmog+d`3=x{j9027HuW0vIgKO}AtmSrFiO(c>wNIZ@R!?LLW#1iZ2j3wDH zWf`OhpcKJmHj~4WH(-ouTamY;SNt@?_#qgJC3BGDIDQkbgke(=lwv)NQgHcvL9ilQ z8{6+3!+!vnR0I{9Os9(+@P&dk*?IrrBQj*kFsRrlDmGgz?(&F~%a-KR=PzHkNs=sy z$c&`egFQj0NLJ(<GT(ocN}?!|HXB1`XA4~s`&V+=4EGZ@c|njsl4WJz>dLS<v7aT= zPa%}c)e6WpRjr>w290sM`GP^JRT&hu(P*AR2H%Cx8^sD$O;e!W_|<CT$uNb2QXDjY zw-2$zW@Dx+l2DN)*ss@{2XOdD*N^ZIt7uwnm_qM#y2p4TYc*7Cv(-A$5$Se&c%rB( zDz@D^>F99WwM7OgbR)%4uh+w8IY(ocV>y2TWnrZACmaDB0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1n&OPyYY_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9aa51fce9d775f169f70d115761e9817541c48 GIT binary patch literal 1599 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_append.png b/web/pgadmin/misc/static/explain/img/ex_merge_append.png new file mode 100644 index 0000000000000000000000000000000000000000..12fc55d76f504140935d5fa422f9a5075431bbc3 GIT binary patch literal 980 zcmV;_11tQAP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005JP)t-s00000 z003rd(Nc{WHi*FosNxW-;$)T3a-%gGuH(UvHg>8zdY-9xu0FMyetNM%gs???v_por zNkF{mMZW2fwrozm=1joprKsemspnI|>RQ3)jlolwyLFkoc&e=DiMiWd#p`6n=&rBn zp~POI$6%JsU2)6oq{?G&&F-hoW_r%-+rEF>y@|ZN?A*VB+`xgozwN%i?cKqGgVF8X z!h^rT?cT(M!ou!_)bQTLg~G${i`4Gl$A*&C@5RRNy3wP>#_+D%ag^Bb;mnHS&yCB> z@#M{(<j$YW&GF^VpySbw<<Fqw(vQy1^0ec5<kOJl(V^tjk>=8)<kgbV(emchr03M6 zw3*OTYfrLEud)710S)b!}rrs&tF=Gv9%*r(Rk^ttPQ>Dj2~+?VOvsp{Fb*xB^D z?t<yus_NXT=--*^+qmiAn!NCY>)x#C;hXH;y6fMq?B2TS;+*W@t?c2h>g1i+<;(2i zukGQy?BlQO<FM`Hu;AeL?&7`e<gxDKzU}3)?&h-Z<-hOd!0+g@@9DJg=)v&l!td&~ z@9Vbl>cjBtw(#t?^6bU)?Z)%($Mo^Z1Vq=200001bW%=J06^y0W&i*H32;bRa{vGf z6951U69E94oEQKA0kKI$K~zY`?UPkg!$1^;v)KUULUEU1#ogWAouV!7?ykih{xC_% z08P8uzzo9+=i$EWd~@#Ev&%65`jNspQS#J=aPdC=LHS%|Vph=rrxEdXaCDB~V*P?6 zOSoTiagtKVQ(H*3K0T*!kezPn9y(&R*|RBuD5{jL$;c}oWwnJQBj0x+hE!(ZG4|b2 z56J|uqU6ai*kJH@XNdN;E;@msASoyeeLdlI2K-Hg!O>Vfiyb6RLfk-<JSpwt1POuH z$A{Y&cse`Wy#}=#6BO#@!i&hmHd?uav*Et3WuQFNGM5Uyz`)%Gnzz7yUq|yS4PkhF ztFRheEux77*lcU89;dqKTir#MXUoaK4P4Akj_d*D?}vtngvyQCK3LpK>BaV2;4y5! zFcp^>3gRlIkf(HCo=X%&Q8JG`mtuU?vnWc&GXk+=|5<z>)+K-bO1R(MTt0_mbAQjO zbuYw{VGA{*NiY=`WVb62QpvD}s*xFtx!GwA)=08cuRN`gIaG!Ep))fzsaD}aS{Y79 zOvZIsXsWB7QXr(2iS{Zh6GdK`j1X5QioEi_{zPxhzn!H%4w>%&0000<MNUMnLSTYP CgEgxF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce4839e02fd3f17b5fd8e358ff204046c38d26f GIT binary patch literal 1344 zcmY+CSx{347==TqEn;1Yb)kzRwvO5s8xTS1=pdpEBQS_s6{;)(R?#BJSj4Jq3RJBX zQDkYPh!_@AR0IrxkdTEC5=cT4vWF~}EH}AX?oB|$Ort*a;rwUL%=w=FQ<a$T<6{5M z{81>>;#h1<lGj7u%Fow(H%%9op-|{MiE#(_c;jQdE<1-e#<7zI!9lWxOtDPx9D+$F za|9Y;+1PBmM2g7e2w&iwoP>oUczW7R8US1I0KR>uy>o^_wbJQO_e)bxulW@b<ZvB4 zo@1B>(HS=8h)pa;>PUr2w*vp69j|&N3$LV{>k!lrt7&peF2@=_WK3t6FL1zCrK1;c zH7nuAD!5GzQ;lwx*-Zivior!Ux<t@i6v-ISq51BG4od>61lETNxJ+QH5ZZ2v>;w(c zr$;)~&Sx6uh{@f|NG-y(<=?}pne`Kl{^u_ZM7rq_Go5lf9JaG;VDH?l&W*_Qz^qE` z(rDcPFl)8GZeeAZfrp4=T%kmSLZ?ImE0ivyaqclYvz3#LAOEF|e_A$BCFnXQ9V7Dv z_73408`uMxdz=u{jY#L*+Na`NlkRVmw$Z4rw*oI<I~TTdU}((ckeqDT`iPf(toCb@ zT??6djMEJURo#rD7SwjRVJU3mIH578m5tcNm+*=8qsIyfJBhqUufSr+@WP;cFeAGU zOx1wur*5ajX&H5xSqLO*8Y-zE#x-)&i@KtYKUhz+mi9wsb~6oB6U@p^NJpMUrV*>q zZCA}es>*=`951s&nb&8&N(4(twsIRVWR$lXrFet*iAB}#cBo*>Bn%3iW`PS*7^Q7$ z_8+Q|3MKs-z-xxVNk~tFw8K^n)nS-0h+9>R>&oGB1*KF!-sCj%Aq~|!O|hzn95ds< zWQ&4YCLb!14P4c6a1JBSs-{>}Ll!034sgw~K0UWdJBBk&^&l3R0~ojKxv*KPW#gp8 z%b<J^8ZM=HN9j|LlyCqQ1x#go!@_geqvySjeW$&woSohR5F4}WAeMO|ZS{hWZ^o@H zjt<~cX=Bt;2A4)*(K*93HuL+nBQc3L{_3j4ufE$?-cl2G_hx4!iJHcXCZ>+~h4>dY zSFdYJuBo}Vk>A|xk3MZ$+vF3p@YH_cBwxfkBosto!jdAwL$+=?ya7+A@<*k6g(9w! zvR@G^meB8Yt<;>!+s)T3aowoc;8%FDtaxd7@E|tX<MBnKJ@e?Y(o*z}vfa_c)PZNG zs-i>z%K`%f)vG>Tv0{ZT@XO_&ueyC`AKI845G$^ZA*NQ}>28@ViTY+6jXxB0|Ihe+ zAGQbA9hF3-<mczxr>ZM7wVqPyI&zbynjb2^vgu!ZXGXE!his~s5{t;!8Lhxdd2+H$ z`a^M1P2{d350QAO=#A%f!-lxV@)Wji(}5@Phm(@(Lzd&2xj)T=+t1GfFXQUTsNU3- z3CFt&S^TUm*_%@dF`1P<NcVl;vpy!2^m&H9U6|t$5mLzMU;Ubr=F|HHSR3Eadqx5D zUS@KS_2<1=;NKL~a}pYy|H!jsP2}&ojk|&;3b$YI&{zkqJQ;7?@f+?)@T$!?Vu1u2 z6*|R)<?x~pmIY>P?D=^xPs_+6o5h4r&fZYnYKX{H+WIe;MNe~RudnS)#<~{;28H`~ zp;7y0eV6*_*%98?uP@khq#!fBAS?1jewNozp_mX%a7bt{Cgfl!CNgYGWLVg@n5~f* t%(lAqYyJnE&CNWOeepej+5QfA+m6J9zXwKZ4|RG0RP3IF7(#Sf>3<opDS-e0 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested.png b/web/pgadmin/misc/static/explain/img/ex_nested.png new file mode 100644 index 0000000000000000000000000000000000000000..15c47316d5d4163d97b95cda99b2e3a2049341c5 GIT binary patch literal 1108 zcmV-a1grarP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002N z!qAqP(SL){b9d2ZYtf>m<h8fzyT0th#P7ht?ZCnA!NTss!|uez@5RRN#>el+$nVI> z@W{&W%FFS~%<;_4^3Bfj&d%}9&+^dF^3v1u)YS9U)%4fb^{cMtuCeH+s^-7I?YX<_ zv9sxtmEUxE)|i{&!NTpPsL;d2(7e9v+1d5IzwF1wx2vUWos>nDi!Y6V8N<SK)!C8X z=A7p9r{wXW<M5#4@SfuCp5pDD;q08@?3>`~o8Rb}-shO$=$_f!mC@3Tzr1kL*o)26 zebU;8+TxSc+KR}^cFoU%&Cc<&uw0mqEU~Ov&d-F$$aBxniISDkwXlcC#=6<xjNRgy z+TW7e-jUhekLvTc$jR@iqGZ|JkFBog*xQf2zwOuBjJLS!xVh`s*o@`wtmEsW*yMoL z*Nf}&z3K0|)z^yM=aJRciPhDL-sP6m)QFdjE7;qU%*}nTs8!L=iO9rx!oF?G$b{0> zhS%DTytZrH;g{Fej@H)nL!K(600001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0t-n*K~zY`?bYj3+CUHha0E^Sm0C-!f`UTD2bF{cA89RMMd}k-_8X`@6D zMDcCwzpmmq!zFho^0nPBncU28_IB=WSEKnK57DI6=@B#ZI&Bj!nhh;RQ)^pWyU}cZ z)A6?RoyGFL>qB>s)oQibdVBlq-DU@7w9Wkk{RS54bh=CqZ4J>G20jkDS^IJi4ZF;` z8lrbO21iC&#g2{)nR@g!3&`nlGsS~(TRx#$;_)EO3xVtkGWPWA<#-<`!pC#oDzTG@ zm-7e4Cnl!^LHPV-`fD&4425UD%|;##g>e44==XU{gcqWVOA$^@mY1u)d>}fv62tcu zi?6P&^D2@+DDn7(31MX;iI<(+h;RM?6?qPr6k<u`VluY5#Uwyj-DZ&~GD!iwmYp3E zNvTN!?e11h8X!#~86`=e_H5Spl!p|M$tel4d9vA`ebie9IZ>Sj{rZg<Sws=27lu-c zC{alo_Vx${Bq~Y6em=jiHXz9~0tdl-K6I!$8ITL~EO2y0s0Io}dif9vlTN=_Vvz7L ziImF>GJZ_B{3m6ZPJE}8xcZ5m`Oke+!p|<Q#uX3w<m}?|il?`W$kJNndTTqC$=!&O zB+G?jsp7x9xaAm4DY72;gNf4L^Q&7%Q+ieFtE0i*;iR56euwqsx`u@l8x{?Wqy`3G z1LL)UA^xw%J#C$lG-cRqEC2uiC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$c zGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLe aHY+eSIxsNGmsP9)0000<MNUMnLSTY)!c1@g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c0763337617f9ffe8cf13ba0f47f4cbc228c5e GIT binary patch literal 1741 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e8a17d409343ea937e43ebb76e8ebce3cbee49 GIT binary patch literal 1679 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 ZD=;-WFfhuORjdF2002ovPDHLkV1g+E(G&mx literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_recursive_union.png b/web/pgadmin/misc/static/explain/img/ex_recursive_union.png new file mode 100644 index 0000000000000000000000000000000000000000..66952ea454e3703dcb08251bd2273193aacaeb28 GIT binary patch literal 1224 zcmV;(1ULJMP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005?P)t-s0001q zx!X2~!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_`zG-s;qsyLGzJqh@Q-%+2w=zwN)l?ZU(F)710W+4RoO^3l=q z)YSCg;P-*9LUN@xnY?(sz3iu{=c=sduCM9E#_!9_@xH(9!ou#w#_-nG^mC;*r_X10 zsycS7JFwk!QjHmRt30ycc6zZujKETQu|cJ%<dC*(*yYQi#9oB3MRKDxqQ_vQ%44U^ zW`?#&cB(tB+HrWUKD6U`wV8gwk2a0LQ}pr4@a(tn?6&Xfw)5}D^6bU!<+1JKu<YWm z@aVy|=X~nqo$BM9>EWC2=(Fb9mF3ry<kgbv-mJOnfA8zI>f)T}-<j^_vh3rp<kXSl z(vRufs(PNOy6%GS>9pzKn&{q{=iHa<<FM@Dt>n{?<I#@d&yDHXsC=|Tyzqqc?Z)lo zvGC}^@8-bj+^Xr?sp;6K?cuzZ%w5~PiSg>g@8!Sl;=SnCr{~qB=G3I@-MZ}IuH@B` z;?R!h*QVdchTg@6-NJ+A(V^?#t>e*;;mwQZ)TG|TgxtV^<<6ku&Wz#Air~qK=F+3x z!Ghesf!n@+<jtP$<G$?Py6fAx<<Fqx&Y$Ypwpcc+1poj50d!JMQvg8b*k%9#010qN zS#tmY07w7;07w8v$!k6U00Ih0L_t(Y$75g^1>^xnCJ=y<#A#t-W?^MxXX4=G;^tu@ zQVTC1zknc<kg$lT7_nMNw?!Q63n)p*ixQGjKvG&pR!&|)T2V<^MOB)R<&tXZ8bB?Y zTG~3g(t7#^hDOL*uzFF-*u+!=rxxs9)G#x*z@-Jd7o{w%tTk}?1-r1MjV;hGcG4gK zB^fj<EbJY?TCiG<EyOGw9i6~>aJZKN(>M(aXP_REv;f1z+0g=bbYa!PVBrGNg6c&y zE$GHsxMJD@@iq)#7-!*Tfnhl$q2L6P?j9KF2$E260x1tqFN|~qPAIs6hL^VmnqMFZ z1!u;P^700z3Ljq(fRfOJf-}iV`hlc<{R0Anf_+0m!@?tc(LxL(V^~CjT<see6&(}n z8yXj%km!r%atvE6lE7M$Q({uneADAIGPBUNWP^PHCBa&9z*=(i@(T)mi;7E1%h0u; zIvN;W<rQEpm1$Ll)xI^gb@dGhEf7DUI$Fb`yrL15lAFL`1tk&D3{C~8j<(1F>Hy^z z-{$b5#1`Myw)T!rge{O%fa+*?uJrBd&g`l4?d|KIFcHZw;8cL!(G0$mCYMfW^PM_v z!t@zPwt!Osc1JV#*3O(YyWMxr+<EgCAhbYI0d_|-_%5vPow~?(@sgzrmSKb#c1Po| z9FL>%0_={)uLY~4@dA8~9tHFV07F>Y9b_N@c>n+aC3HntbYx+4WjbSWWnpw>05UK! zFfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GK mIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTYtrHx7e literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_result.png b/web/pgadmin/misc/static/explain/img/ex_result.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd7b5904f9b304709ac6aab37e24dcc06d233c7 GIT binary patch literal 1320 zcmV+@1=sqCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002L z$<UU#(67SKeXh~4!_bAX(Osq0Zn@x(wb8-K&}gpOjmqed%IIXO*vQS$YP8;l)bMe> z<bu!aVX4@+#?YR;&}^sCf579B&FEmJ)}GYufxh8%tI?>y&|Rq4YRc_yz2s%c>~px_ zSfSIA(d>o8<yxZCm(uK6qSJ1{=25}wjkVEryyK13?q#joj?L+~#?YVI@LHwSTcFW` z#^!Uh-Idtykjm$8yW%;y=Uv3<cDmqo&Fy`{<dN0xWTeqv!RRu#=5@;IZp-X#u-cN- z?P09iK)mRBz~p+$>VwejipJ$*z2zga<UG3PRl(?g&g_)c?q;&xVZi4cujDnj=ViCx zTEpph#prd#=v=(zEVboDyXJq$=zz%RWX9`=(d|CD<!s68Q=QRq$?2xQ&}6XOaJJrj zx!-lf=SjZld&TESz2|<->y*ywR-w~O!0LI->S@2`Yq#KKzve-^=xegvb++DV$m?jj z<BZ7Wg3arCyWyqU@K3knEo+Lw00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0^dnQK~zY`?N#Yh+CUT!A%sLMsaGh-LM_OZl!8#apdwKLmBRyy7FwkURz=05 z^{DN?-f#qVLv*HJI{o0AVTQN6zxUqnUBR$t`S+s2aTTPh2@R$Ze@_Uhr6?^eX#=!w zkidu+dYpM2@p6b79vK~LYpmgw(Ik4&kDGzz5roD1dV(B&W5e4B`=q1wly#1~+^jML zcsL#Z*85J~R5W&<&+Tu6-BT{7A|X|P;{qx^*y6$v?}zk~X*x7LLn!g#XXoaFl0t_g zAIP46<ARx1fJ7H#9?<#k*9uEIb&ut;cg5uICm&DDQMi=5<os$BHaEGpPRal*X-K6r zalBmum3AqcgrAV>8=EE-ir5<7j^*+nDazi&@X2h!2ImzwkBpdc1Oj$;KNWK&&*v{K zHc_Fp2T>6_XL(<6MG=Sv0DC5#0-#mAvC+Nq*9v^kIK2l8vdFM%Et8knvxnJo1c6|c z&4c}KvKHW}Vy0H@L~i3sM*z8wP6~1|m|;789O!rkC-wRX3IT({=^1*&oHufd5<hTM z>Vx<$E{y1rNF{wq{1pVhD#p6C2Rn5oh%7L0oleB1N|4Fp`jMQ=#pw)z990@QuA5do z%zYPv$i2ZQ&zL%%$z6BtR(}-AOZ|1ZsiIV3#aX_aKKpI?Rtwj<S$$bw@^{6#TF;1K zr{3RVX9kpAD%Y_0MwLA*6vA-iVkfW3ieG7@w;>~pUC1Wk{1EpWn@(i<$E=y+6>NkK z&qpAySa4-uHvH^XzT03OH><a{o{ehAyMj8w$h-WttQ&NZpV96kV4My?L0ABbMGMDq z*$yScYY)=&)1fH`v<WoU-7VJ2U7}9J&`8I$z8yYm`gKnZK)LWFQpDw+wQo`T$%m=d zzQj%A4ia8s<V50kDpFI}g$%88-LN9{Um<<~F?K%Tp#n<Vv$^~qaIuPR*#L_H0A7VD z3nOkq=7|r|v-~&m2P92<JOAsn6#xJLC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@u zGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL< eG&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTXtOrt>n literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_scan.png b/web/pgadmin/misc/static/explain/img/ex_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..396dfb4feabdd85e081bf8336304129058633c5c GIT binary patch literal 1320 zcmY+CX;4!K6or#E43U(&OiX7G0Tmtd5DXYmgR&F@acWZxiv&wwL>3hgrBoq~lr@it zLJ^duAZWq5fw&ZkC=h`X77>I3W&snjFJvdI(x|^WbI&<*@7(X#z04qTpskIa4Gade zJw!T4v82aGA-}XZR*;$vgTXU`4u=peEwhE|na4_cJ>&OMPHdC^GN?%#(geLygmo&i zN3_g;wJ~hf>0VV*pQ>a+SI*I098_lwt84kXyOa8Y(V1&wnnwbI)t>@VyL>~#^s#Q` z-ez%7n>4gTN@YnI!|M1RSrS`*eOyDod9RKoioG$+D)iJTAoVnDW}2o~Kn4Y*nFci? z(4d5jN=PdLbt2HDg!CeCRtX6-W+}%-_OSp37f^A587`pV0tPWSt}w|tfRYQSEfXG~ z<pD-9I3_n5EVvjnE1@|h#C^#el^bWp;E2qi;{kdeVBi5}F*q#M8+pK-7&KX20?sR; z1r;<X(GQCC^Ad1T#TXFlOnku12j=+L1qs+M(#`ULMG4q9t)1s%*%ntpODaaswDupN zW=R4rs~Ft^&Eh0>X%f3E0nHYQkNqG4U%j7Mp2U7oF*>GZTDYnYlh_prI4U=^O{(k1 z<RH8(z;Xk43WXdD^Oa1*TAEd7Nz|V$N&2LK-gs{q?2D;G2mL}wJ?au}Fvk}SCEl-Z zn!Q~=7IE=$y}e(yGh*kDXdI~~U{jVK(F*Yxuqnx~>1&_l=Y&sWTE`Nqyi*-+eA9Md zK3zI6YurED-VlgxD2VgQq4T)o<{Uc52dBM4_ns4qT@<Dvt#*S#&6df$?z_JA^7Nd& zsc>|3T=BIfA3pq|mf@Ygu#{_8Ub(bzb>X|nwg*!@UBbMkgoVpZr*Tf=$$yMQS7cHv zJl|yI9uG%_?<;ufhl(nz-b3s9yRngm7!eBB**@c+iOV>**WUgtxir4qH!Q58sBY^X z+t^lqCrqiOuN6j!FCm^Z-Pw}A4cEdyv#acY!)jFJxKh;d#_(duq1<!#u|_inUhRb7 zZuWs4?RmPM3Lb48C_72VNCv(-0Y~+p3u~M&y#z-hvq<OPO#~HPL|HeT-JBnDa|-Q? z%<Wv4nUHu7scz!F?nr$`t8(+1oBKW|Pe5|!z>mbS2==EN8$unCzu)=|NpXJS+8k(y zsf-o0Hs=vz(jedS7h1^)Nk6Egj#I}j#|fGRi^DszZaa6=0t<S~OgC$5;PxXZf91sE zOWU(6NzTED<doV?9Qs3{X(;P@)9MkAuHxQkhHpV(D8foPn!Wy&AP<pDsLJyP%3oh& z_cAYs?`!v|IYy!w<2r@-;@--2?03|0W>xir$OP}|H5oNdm)-MvQ!!rm(9c)!#r=_M zBHea|)}|e>!%!27`lYDuS>)H4O$vGq?bkY|V%O_yDBIEKFR-P%ozXV=^u|^833oyO zaZUL45Q3B6k&=}B<!$*W;*kcVXyLiC3y+ARgakaz>j~!U7+UU*(%Cey-DHB+7FHqH zPj|}S-*ndrRToh|R<X8I9r-f-LcEN{x??i2OZ4-b(JqNaSpSxvc22t`6N*Rz>U)~O z3XiIz)B{0V)^^ow^e^-{bxVdh`d7qN(nH;q3&j)u%b;lk?cGMHsP*lX<>$Ai5W`cV zkEg^CP9(=z0_K5p$GN(DxZ>PHJa7d3E&?9!g4<2N;r5nqb@(5Um=t{~HtjQj+xH3h axJ|%$eg^tVLmyfI*dZeMV8gextp5Q0yRj$$ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_seek.png b/web/pgadmin/misc/static/explain/img/ex_seek.png new file mode 100644 index 0000000000000000000000000000000000000000..130fbd8f53ff5c2c757c8173eb62a1b604555f34 GIT binary patch literal 1326 zcmV+}1=0G6P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=yH~!hN)yyjTym@HuUhw@a(tm>$dan$M5O1^6ka$=CkqY#O&j+ zp~PP6<(}%}obT$j>EN30=(FhFndjV>?d7rN*p%$xt?c5j<kgbw;jZi7t?lNr@aV$t z=D^3Qb@1lE>fEaD<G$n4kK)jc>Dj2{(~#oMjN#0S=-8+2;k;g#B*DnK#F|j0%w%+@ zIG(kKuGw+%>WA&)VD95x^XP-`;92wMfbif}@ZVJQ=6#RAQ?cH30002z+A8STDCyWG z>eeFb)Es@XL#xzmv*LH^)gSEB81mgwaGgbAl`r+=dg#}t=hUR^+_~n_qTtDi-^YgD z#D(V5q}{`W+`xk0$cWs(faK1gsoHLy(PX^vg!0`^^V>}K<977gNQ<j%pw(yY&=l^^ z5bw?o^V&-A%?rQBx1!f+zBxuV00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0_90WK~zY`?b6v(+E5e+U>k6&Tea1i1BihN$R<*($RcX1MKFRGK$JxVf+$KW zhy}F%>%F-wiB95-Go4N!ybt#&-#z)Ab9#DS&%Zx!2<}MUVuX;%<?>#luYX`*kQjU` zlMN9=eZ#{e#K`E_*gHa$$j8UW<wXC)#Ke2z!{p?ojOaytm>8X!l8q66sme$E&ysih zt7&qYC!kO&l?v`wDPTseR?osLMNt~iXti1mw7()hkpiNeo10UDQm51DL2WP?=7BPr zOlHtpEEel?M1_c&BSs1+lgXro1&hV@3{im|lX;^N5wpo;(ZZt5X0wYEg;J%O;ZuCZ zDHa^yu-ffQqT~y3NAec0qSvcYm3fLnRm^78CC#GM>VRdZ)43x4V<?4zPhsh%aJt-X zk2q25T8%Zf8@mWro6YM4r`x?MMbIodjcv`s?sd5kS@roO$Sh8w!6_Vq6e}Lj+B#1* zzIONK8}5wc-65M>-;p8xoPq5?Ah6xNgTWoxp=o*tc0-}?Ubo6-WNU*YN&h}F5MZKA z00PlyGyuU^EFJ{<;NXCUP$H2C^W-qHdF1!+CzB*1Q6`E>EC|7PJWeB$N`)YtNT)MA zA&*Z`6(sm7u~>_s_vus$y&p~s$r0`tnG|LTK25Qg$z)ESkQa5#FPw|RYPB!JQhOF_ z*>zaY<#Kt*vn-njQ6gLqkFQY3Lhh_sJO}ooRAReiUr6j;FJ6yTv>w?);W7ugV)23n zwp6+*OAwdK?L_bUd~1-sJUh$5dGP|1D*;IgiByVwxm@mMIr;J89XtMch<EH7&xM=C zF6@TGtyxq~;j~(<-oQ<*R=ep`xsCif<aX?uGe9#bCe)sFre3dCpxS6Q@1S;ne_!j6 z-?x#6<TXBM$LJK(U5`q=-l)P|v)QaYCdl9&YgGv`2__7gbiIy9qk#$c@nh0%Tq{c_ zMWvPEu9M<XmiBo`$6n9>cm4nf0rwvzb1L2d001R)MObuXVRU6WV{&C-bY%cCFflMK zF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGP kFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f_kQ{fB*mh literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_setop.png b/web/pgadmin/misc/static/explain/img/ex_setop.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a9b1983b5b47c96ae910e73ab4260ae9c28b73 GIT binary patch literal 1143 zcmV--1c>{IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002E zxzL`V(1?rCc6!ljZ_&-ct;w>B#-wM%nNGrzJd>5te}mbYo#C;w>b<`0$jI=)!tS)S z>Yk$FfrZ(}s&>qySJ}LM<k6by-Kg#6v*XQ`qNLELspq@A?YOz?x47%Bu<78)j_l>D z>*J&8;hW6M%aoVjwzuoBvgxw3>bkq^zQOKonbT;Cw%F6E=-!y;+?VRzrRLP5*SC1B zujqQE*JQ2NWs|?=+Lq|snys$rs;uaQsoGkq)?dWwX2$7un78KHmFC!#<=2zt){@q> zb)U22NtVh}z2-Hy=1RThb;#&boz14Or{vX=<kXSo)|jNH<fy9WTeRLOv*bFs<#o5* zUyi-x(~#rRkKMwEAh6_t&FbUOj<dAt7_H;t&Wz#Ai>j^WVVTb!u;hfp;!=vh;meBO z#*ekO>Wt0lK!(EL%8BLApgM`e53A#l)9m2Mh~LPG-^YjE#f9R_n%=~P-olRE!h_qr zgxtV_;K!5Guy4}DpWelaCqTqQ00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0xn5JK~zY`?bK^i+CUTrVD7hwTp9u~3K&4efQ155Dpjm4f~c)k&`L{%-n1>) z8Vm%m{&hD%k|mfKr!(y*&NpUw=DfQ(dlZUEP3k|EQl-{twHmcbIry#98;mBC(V*AK z0c6TNZLwNy_D3iJkj{ZQUHHrlPB<~gy=WGlv$#E8ug7AuTIbPOJx2O`et#ek@cVEQ z(~p4#WO2zm9bC3Ac_=qPq43IMANT)2Boc{6p2Xsg1qngSR4_5mlTc_inS9EFXf&02 zhC3aSREyMFdQBwH*EcfBO%4E&da?EL)fS!|$)-f@i8MsEbNQXZ?%w{O1t(s=IdEa{ z9UyO)4`C8M+9{SY$0rd1ygNNTC_~YdQ=T+TwsVE|#Zvym-aY_BQK?j7P#cx`;~Y#@ z*NbPxQepRaGbMm(wdRV8r%``OjF8VqUpSKa`fZqr1GRJF!XOaM_w)$K<<I)$$4{|E z?Yv%V7zLtrAHsyXEd1ig#_vn9Mg5AVV<tJ`7D*pe`=HruLPQdb$`$xve5NY^u4%^j zfaCL-0Jv_EZNmdDS!~f_Sppgv`A=CNwrBy-V&I993`~e0m^z<{1x0q?S(Y2i<{%R% zy5-);Sjr4PEwt!%S>{IaFeOjS2A<dne{2A{WhN_mVq*{45?=X3(8Ek!_M&$)_K+p( zBEhYTPJ<wC!A;%vn9e=xqQ8_-b8vJi#oJ7y!L+k7OG)t;t8Y@1`X_Y<dEniZp!V7a z0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFU zC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ov JPDHLkV1j^qN`L?W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_sort.png b/web/pgadmin/misc/static/explain/img/ex_sort.png new file mode 100644 index 0000000000000000000000000000000000000000..1d46fd34beee098f997529bf0b7714c52232a2df GIT binary patch literal 1157 zcmY+Ce>l?#9LKkGD0JGb!<|bOQ+Me`PIBs@X131ubm*x$mvXaab;*yACb5J^<yUCU z=?G6fnfz!u<i}*hkYy7xW3|nXjiOR_@wspHSATpy@8|t_KCjR7c|Ol4eIL!oZ1p#* zQ7Dudg-rBA)cHdg8z6b}L>w1|LZ92`8{m!DQ{|nmX`=An**#5DzO7UKZPUMtXP6Il z5fWW|pN=clXUJv+$_1mFs&#^Aj(62w4Qg7mCQzhhh$nO8bCLPQz+!<`3u9yCLG%bb z?15U4$&kq)mBQ#~6BITAuO9LqLIsSB)IkpP_6i{rRI10&2s?LDwdh7Z8fJ@NCJm;! zFd4t3ITfD?Q+k-tfKm+#6{x2Ho*jVkUqDF&&9OlR$ex0982Sc5B7<QifWi&bjP3!r zaEsx0$?8cB`nK#iITTstVily{c^X+e5er>i<q%g4k%ho6fRJ1W5&*YE99$-0RE<W} zX*u<}b08K&QxnwJgHU)0{BOZo5Q%sYYAS}-7f?P0MUzmdg?qD*qJqS6;3y$x4DvM) zseqCx$W=qd3>dXTM?bXpLR$}rBv8e3)XBr99y8x4qpF)h&;TP34lIsGOB-m{TFz%8 zmqJJT(fm=Knjt1)R-Gi%qYx#33{uyzT`1HF4+_yMfZVAcm^py)vTU8m)18%`sKnhj z*<uksYUi1eVOfJKPs>_|AHuUzvW>}&>XtFnD#12=5jSD-l}O2Xy6AEAsv_w~<-a~= zR<a9*e9KC+;FgGmLH*CMbBgT*1FGqRFG(blkIk<5_s=(bzrrV0ONLT{JvvNXj&wR) z>7XZDI#BoKl9GL|_MWroq;CqTDQRU3U&c7L*{b^OT#I7a=4*Z|__`WB7ft(h<#lmL zwVU<juuHW=)EJqm7n3feC-+#%HCxw=uD|m{yYOyl`E(|KL();vVdHgcQY}`jeA$Kz zd^GU|aTDfZM~Hc9Sy{U?g_H0ClY?C)4vFx^B<8H|$3?8%P+fzuPdEAthoRteGj^qv zp2y-%Cb5#6EEi(d{<;x1@Ul9Xj(^`H-CwfeY>d+eFuzNvy3((g8#?Rm4)+uXRZ{0S zek&Lj2&|vqTX>h8z4p+Yu5=*Wb*%X-%fX;6ZCeB97F{VJdvHeYIL!geO(qzY#fd~4 zgP|L%u1gYzNTmVY-#^*ix*}V#)w7h0IfJh~v<cg-uAtgBZSQdJ-+WSx^D$TOOB4TV z&ougHZ<*gtEH4SK60NlsIlMIuW@DxNaj!)u>tp7<>2HN#d3gq@q^0Jug@L!_)33u3 zSD40j=<&?;yenlDmRu9KMFjKSyr<uxY0vOCm{D>(4e9y6VRvwCmgKfwx9qwK@bjUR zis9q0OCHVF-XIovFSc|R*2(*Lx0j!tMXN^#U$e&f2a$)ekM=$o%{USr>i$P$C?Y6l zf)l~f$=Q+M6yQv7ciHCd;_?IGCwBtDjc339GvLo~Mi}$-CxEcyBk-Zyo#6Tj=q}h_ PfdD9qH;q`i`*8CAb@5|F literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_subplan.png b/web/pgadmin/misc/static/explain/img/ex_subplan.png new file mode 100644 index 0000000000000000000000000000000000000000..e13d7794e91fc0842702b0b34c1a9b61607dcf92 GIT binary patch literal 1283 zcmV+e1^oJnP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002O z!_bzQ(SL){ba>NdYtf>m<hHo#y}#_l#qYwz?#9UP$jI=?%J9p~@y*Wi&(QMG(el&N z^Viq)tgh&<vFNF*=D4}*zQ66j!R@lN>5`V;n496cyz8c@(AnDc$Hlj+rEHy)MVE~( zje!}GmC?n;b=BCB+u@bv?y2JJpyBGA(b0>*y>Y_8Zq(O`&Cz|**oW5HjmgV)&CP_q zyl}CsSnBe)wXlcC#=6+uj;W$#*yDlM;eY7uxXQ|X(bI*zwrqx}WKxY8b*9HQh{34O zXl={vL%r!uzvx%P>V?$sl-Tfk&g_TN?ycYR5Ub*n)$gj(YI2sLtk-VAk2du2$?)v9 z@9DJj?Z)lovFzcl@ae+p;+*H(mgLov>)x!v$huvZB(B<V=--*+(T?ies-Crnc&$CS z>3-?jshY`Moz7yq?t<^;!0Fhh?&7_NyG?JLL&vIhi>qwE$G7O#rsmV5>)g5C#f9C% zgW=4J+`xh5&Y;`Af8@=c4PV1400001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0=h{=K~zY`&6Md=+CUh_IT8h`QXz`eqXw2kLy;n)g4XJmdbG8avTB3Kp(v<$ z)p}e1_3p-?5Zu7nnNFV%o0)f?-@M1}Mx*)X((3dKs}!TxX;p}pR)f)GG8$jBwRd!w z%`ZDUEmpIMqcggeuI?_I0%_~9**P5z(YJQL>Qz?8^x17DJq=;{x!wU~4cdV|%WIZ~ zu$^Xx5QDtK35c8yeo&)jELJMwVp*3&xINyX;bB4W`rcrMwbBt;yniI{)+-1?FfbY# z<5dwki^CHb36sj4;gCDzP(xg7TRUOE_;`3?5(g$H!Vxb}L0qhf<BXVz0ua3qO*$hH zHH5VoIL=<X3)B(ZiOt5=WWh)fsJ71<dhlKp3=LHn5NrmCg5jxYL1vmmz_>6q?R^LC z+aGBz3y6${r7U>JZlAM>UNjEhXh=TF8Nd2bRuFzH;GTIO2?j%Mzk8N%fEdW$AV22w zL@?s<g=QOEOV-}=<mI>0-wW-D+06_Mp*`e&BlRIa<9G3lpVBjaeSfJrI7i?75F?V; zhba6A>5ka^!s61W*yk_H%U@$pB6W_~LOdQ{ip?)B&3~&x5><%OLCKO($?{#QQC=UB z<Ren&Kr5@OYb)r7D5loYlSrKdt)|oIH6(6iGFem^Z!W)?&s9dPbVz|M5s8^hVH*(_ zo>gwAm@Mw(G_XV%g#!oHwzf7zl+6?hyND182=m3g{rzGd!crMCwGM*d8pU;Vu)TYD zgz$MJ63OJ|-to!teyLO{m&;J$!1{@Z<P~R0Bq4++r@u~5@V88|)H+C(^;9Z*fR4`2 z&M%~1s%8btQZKa*97stu9$sEvoj**h=5i_>8k8**uFuf<<<-sY<GEC;&VjbCuSwwQ z=Jy>1Q997kA*u1=_V(_Af+!tz^Qco}$N!-}nbr1E9_U2o0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1oA>oooOA literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_tid_scan.png b/web/pgadmin/misc/static/explain/img/ex_tid_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6063a1af031c626802911fdca598983aff7d52 GIT binary patch literal 1074 zcmV-21kL-2P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002d z;PI2T-@Mf8{{H{L*6o?Q;ibal>hbyT^!nN5^vBrl+3WSI#^#K%-OAhV<Lvi^t=n~> z)~3be%jEIR<?+4P?Qx#e)#LN7$>)Ek+0f?l*6Q@d;qbxV@5$rvYnjrc!{ox+?t7-# zwb1FX%;=%P<Hg|a#oq4t`u(HD<awmm>Ezqh$F9h;kiMjKx|(3PkxRstJB*5mfq{XC zhlh@ij+T~|prD|vtgO7eyv@zc+}zyo@bKZ`;laPVtDlO=oI}p1PuR6w-oa?$%4zD; zYVFo~;L^J5>E!0-=GocV($dn%$jHFJz_hfqs;a7)nVF-bqn?|W>)wU&>3;X;Y4PG! z_2EYK-Z;soXy4!8*4Eb0(9p`t%EiUS?d|R1)xgxbiOHZ?)2mYZ=33Can9k15#>U3O z!^66|x{;BQ>gwv<&a=<QxxT)>xVX5tx3}Kg*UYkn%e$bxy}jh*<eZ$G=;-L1o13t( zu%DlwudlDArKN?1g_M+(;^{T(00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0qIFZK~zY`?UY$l+E5sVm1q!Z0s&d05EXH$OJzw&f>9JvV-~<xtzpr&mJ)3# zt^4}dJ;CwH5a3Q{crP>OnfJ;0@};Mzn|G656V%rsV(N#@1DyaC>j%>yg4)_VZtpi^ z4$R~na=AT7>*IZ1AL@sFZhUwc9|;5piB`Y>L|~&3j^krablejP42`#Fv4k9O$mI$; zF%N;*>=WT2Y&Irr9@rh6L@)yJTD0r+VpD$OYqp`G5qH=Twobo1f&7qh2|N*)`RMCt z5>^5=+dBb3rrVuclg!S|FML{Dj6`FxSe&F1G{YvB49;`QE2-7B^m-<<5!u}0xots| z<ZO=2OPoHy%R7<P^ye?Td;4GaGY3ktP$(AJk|>G{P073tp-|<+t)p+>BR|ra<Kx}6 zp9P^(`c;(}RaK?3e4@NYvh3lhmf7D8Y$NrD70Xgh{acr1xh^r;=Ey0}bN}Z4ADn5# z`7_Z35rLQn@fV!3T@cu3sYXRZOw?(q(U+=l1rYG!LIqTS4wb1%)v`)c*EjlN#riFI zORLpVMG%CdCdSn7?sHM{I%^=7WY6#Nxs&Jv80AAeN<QWi_cvX!_a&yZ5Yzei!HOA( z>8=<EC*^g;nl5r9OG%cY6BHS5^LNqB+sG4UmhG=%BJ%?P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$g8msoqyPW_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unique.png b/web/pgadmin/misc/static/explain/img/ex_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..cb70480be8a4f49369d9a974ce9461284d1a4654 GIT binary patch literal 1238 zcmV;{1S$K8P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002Z z#KgUKcgI3Ps~Q@~u&}o&Ddc5l(9X`ss&&DSHnvqK%tl7dN=mayB!;PEQjHmZrCYPX zru6a2@a(tm>b0~uF5<tRp~YT>vPSFWp6cS9>EWB(wt%)SEA8a5a-%iq-I&LARP5lb z-DPF(<-exPW%BF9vLz+pz?JIUs&=Y7>DZ_2+_~o1l-8qo)LdNR&yAk7hpyUjc&<L= z)RExHh~LMC=Fy_RTtmV?KjF-Z=+~yT<a*t~g5%7duOT6OvqIz1kK4U}xG^!fML3PY zQ|HvA<j$bIJ3G^6X1VKs(35S+RaLw1gT_uymdstaH8rt4A-G~H%wuG_M@zb8Ws;TA zW^2)iL34~eXwA;?y}#|h!R^Ar?#0IN$jR`_%<--<Hq^DqyuItEspqP!=dQ2mv9s#7 zx9hx}zpN}W)z$R0W_!S=%C9#);NbVg#O%qp*3r@OwTrE~yX?Nd?W<8{vvZEQtk|zV zN|H5LgGPX=ey69T;D1YtlFETR00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*y&TK~zY`&6N9F(oh)3hs+U!xs^aDm&vUZae{%Mz>t6d6NpNgVwgoYFIh(3 zy7;emwsT-WPoD8Z&*S?eXP>?A`{nFI5QC)~(-9-qn4TPw8K(^79c_;qX;>yRGhrkM zmgDZ;!yxpe#VVK0K;5Sag0tJFa13pkb~v0)7iDnswA^I|Fc`!t6CSVG?Df&|5A2Mc z!yy3hc-(%<1rabC4w>YwJny3XHeUcC4=@N!Y=Y67XxiA1bfc8ZIN0SO&+|UgKRXvh zUD&C47Dj2YfB}5L&;mV(@PZ&Ly2G|eBm_^E<{w2_CCX`sM~Fq1<B1`}C&Xea%&Iq; zOraAtn&uS5sSu)=8Af8U2<cyQC6^Jh6isJYB}$L*I2jkk+%OUd1{d?;LMoL)BePGk zEL;+-QB0IFnW0^bN?v7?8Vr}lB^C%K$n~|kVljbU#y!RTm7(NDzETiDp<uWw4oSsV zYGtpCl;9o9;t`QtCtYGLmn$hZIa_^(yU7b1^-3X8DwULAxGEqp-;0rcUaP<81*7Gw zBy{A<kv%cHxiuOAn5}W8+b#20LxQz!W_B9d5|f&{uUdPr_um+(w~{uGN$q#<KYaXj zKp75?ByAo;$g$acEF)SxhLA%)^%){~kHK9IDF4aP7lhzE1{2$1^xKlu=tsIy%GLP0 z%U9sB({2~!v2K*jZ{34|T{`aYNox=7f;@(n{C?Iu7(mXM)eH3mdJKaAk6o%=pvP`N zn!Bw|K76H)j6C-5UF2YX)XG2AV35adO6;r+Ja($S4C^s4@~?d5s&8bh#{hC(D_^Jx z-eXexH}KeH7t!J|X}^=NZ1#fD;;{zEtA5=J<`#PF|I{BM#JXLtE~^v(001R)MObuX zVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn= zI&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f(A@n A@Bjb+ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unknown.png b/web/pgadmin/misc/static/explain/img/ex_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d54f5c7b253978b96993ea260828a144395095 GIT binary patch literal 1088 zcmV-G1i$-<P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-s00025 z!qAqu(2ljybgR*YvC*c#(8$fuxW>>^ozY{g+H$$zaJ}Pq#prd!=Xk~Eea7c~!sL0n z;BT|sS)tRx%FtS*)o#A!TgB^2zUV@{=s>&YKf2~ayXQu|=uW=pS;FaL#_4Uz>V?ql zgTmx#uG*ix&}^sCZn)r0!09iw<{+@-AFtyivE(VU<S(@3G`8hBxaB~(<wd*ZOTFe$ zzUOPl=~<%FSE18r!{{2W;}xvqRlw(3!RL9*>ypmuTB6fvyyGgg<`JvnU&H8?(CcKb z+6}7WW5noy&+LiA<Yc7LR>0^9sp2xV<VL*aXU6Do$?BHZ?`E*vFt_Gl#_Mpx=3d3> zQNZYfzTthY(P6#i1*qX$pwV}|;(pHSdCBU($<S58=^e1-60GB4s@Sl@&}p>ZUZ&P@ z%j|o{>5S9ub++Dj%<5;W*ml6=ipuD1!|15M&|t;sdd}^2y5K>(=xE66YQW}z$LM~@ z=wip~XUObp%Itj4?KV3{{{R300d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U z00H_*L_t(Y$L-VoSJF@z2k>#Zm$&&66HySyHefJJgw$z(fRdI186mP%OejOc)GU0- z>Thp&cTUGnWA_LBjqi^;_jC5#=Xowg_45ER0W(yCfW=C5-iGWBdSGy9_=%GlaUqi- z7)9=}agTSxH_7@rUI+w3XtcKw!x1Su^>jKm6Hh#wotx+6KyX3qS=8e5Xfl=jOVUex zCY$SJ(DF(?f1kYIGpjlM+Q3>O|MFk*N?zYUx};D{l{E6&w>hhkH|4iEy=IG*tr8}& ziR$)Hxu#$u2i^f4va_4qyCc)=fD6L<KCfW%UbnKkRKg@awqsLAR5&PNlF7pVi-x=T zA@#A_G0)+r?gu!`8IsoWZc$>r-g5o!YDdRuOx8EdI)ya=f(84cqtfc00Its*zP`{t zvGm*-tI5)xw)yaY^JDU5HB1@DiXyUq6VF9xpNhu9hUnU)HhsCxm`TK0GodYv9AJ>K zpwO8V$2+zpw@(TFp)QUR#cP=s&KF1o75*B>n>;TB;RT6Mw;+beHz%@@2+C4n@q3xe zxX1(rB0fx-PLf_>Qk9e@SL44kfRHrYjx{x*Q0S;ZNGK6#A=nd5v?4T3cRC&Bgw()6 z&n4?oZ*z4HNy+sL?wE4ZCuHQu?RfR}=da`6SyFNV?OMnlOFxg0KS=w20#>Z+^Z)<= zC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!q zSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMn GLSTY1nJ@bQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_update.png b/web/pgadmin/misc/static/explain/img/ex_update.png new file mode 100644 index 0000000000000000000000000000000000000000..a45c53f83a0593704855bb8488871e8e8c9be701 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003#P)t-s00016 zTU$1W!3nA2a+aZzl9IuXHZry4b*9Hbyy(lKSW3X@*Qid%s&!q&>iw+&W5()h$LMIt z>~72Kb<OPByMEiff7`u@<Gpj-zJT1nfd9QPd(rRQ!GeU*?%l(Kgwyce#Dw0(h2F-7 zjMVPm$A{m@h>_Lq;K_;M%!-%U@#D*$;?9iY%%0@Up5oAr<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp{Fb>D#L7+PCQ5nd;rD?A*BN;F{~+tnA&o>));H-n#7It?J{P?cclX;jZoAyXxef z?BcKO;k@kQu<hls@8rJi=CbbQv+w1=@aDkp=(F$XweaY|@ae+v?6&di#PaRM^X<m- z@W|M;qjdlP00DGTPE!Ct=GbNc000SaNLh0L01FcU01FcV0GgZ_0007=Nkl<ZNXPAy z-B#LA5QQ<eL#ah;5tS;UMbwA_5<v)|fIxsm0YgCuG)2mv@BaclIp+XDLzfq>)m}Ik z`zl|u_nwKx@;3iqJ}~+$R5OHe*le~9W_M+Eb)VV);&7ZYr@MQ57tF=s@$q-Y6tOKY zFWZ<Eq^rzltJUgYHW0qY9ImfBj+s~b$~)|Np_(D^I2a5bC)(@vMljMeZ3shERr^4m z0k9j9!To)$N40l*d;0*Il+U+8O{EeF5Mun>Zl6PH7^x9N(m>1S^C~n`i3##!Jnm*; zhV*LqVXP05gphXrI;BEA5sz0XlFizcG0d`H|I-vdaf)Ui`bxFjrCB!Z-`K&F`2_lG zW8HeL^u3$4uQLXA^nuZXrj20OZmUD+*A=A;U0IeplNZl1u(P(dwqr=q)KgrQK@JCl z;>^E+p@=3)q}Ws)l=#)94014dCK_tO3=TIzaIq>bwt5*3%TPQ!V{>4cXY2w@vpi4H z5p%f~7?%#4`cmO#jZGLtp*Uy@&3d0|w^~NK=oCe<1FcLZ-GKRfgiQARl7;%8Pr;%T znUf=*08efhU<o1hL;@WKQ8^qA7C~fLHUsG+pZ6(3LA}y4RZ?t@Jvm83((Co|<_PjH z|Dvj=XrUD8WCI!k&sR*5kA}v!pSNfJ6<IEJ=yr%Ul7estl~^=#V{VN2CpSP8r8wXr z>T$a{bA%j*5fQuxo)|>jZr1{YRBA-{1CJ*HoZICJnIoNCF4LOJQi(<*B`9&BQ0dhg zYo(KD3q<dDK30Jnj^of*LV-ZR+!#3wqPz#EaOo)mPN(zS97+20!yp>N#m*4FIU=Af z#HdEyIudfZoB=prjNI`t<e#W9MZxd)7yi=N)=U1%xA~vu4`}JQAOw$Lx&QzG07*qo IM6N<$g4z^C1ONa4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_values_scan.png b/web/pgadmin/misc/static/explain/img/ex_values_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..15b5ab4079cb8e2c015b4f5f10a3dbf8aa6410d3 GIT binary patch literal 913 zcmV;C18)3@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-siMiW0 zh{12o?m@ljMZW2E&hL59?@+?(R>SIp)9{Ja@MXyCYRT+x%IuWb@tNB3d(Q2G(e0$& z@u=SNj@0gw*6*+3^985jNWbYDuH#$9>o~XNP`>9?z~@=P=Z4YkYscts$mx~W?|Po8 zrNQK8meIkFHu36*?c-qX<6!dYhx6)(@8e(Z<X`jahxF@*@Z?|d<X`pchw|iK_Unh? z@Av20E9lxQ=-Mjk+bZnaD(>4V@7pT#<zLt8_37Fw>)R^r+bZweD)8JY^yOdH>GbpD zU-ji*_v?rF>xbLDiPY)z_T^vG==1U1D)QVa^V}-;<zLa~^7Py)_~l>q+$#9yU-|2Y z`s|0!=JL+v^7-ap`|O6y<?;31D)-$g_}wY`=3mR?@%G&+`{rND<M8?2DahmS`Rs@M z?1snV@W$fr{N`W%?1shR@B7{<{N5@3=3n>SDf-<h{^no8;O_n2DgNw+z~An<+wA_{ zDgWkQ)amoS-tDc{=`>ap0ssI20d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_ z00FH@L_t(Y$L-b0a)Lk*24Ek?nFomRW_gGUK~X^z7hFIQqoPPyTuOQNU}g{;#Yj~u zhm?Jq%hywM|1~5M&-$-bf~P9QA@C)YD!#&4B$dhJ^6-HRlK><UDZb@$)Hi|e6h+aI z7lL#eAd=5jtC&#LT8)Xk5M;BM1g#-eV_6OzX@=ukmluLU0gw}e6wC6MaC~zhM3C?# zXpU=qVA33nA0Xiih4FYO5~N%P_eS3qM6pMZN(IEs1gO_R%)p!pq$!4J!B~W0dA{*T zU_hti6P|CPal)1$2<_;=bi0@Y8wgGI=I8hOm;|k%FdTl$=-8HJWkw8nG`bFqIFuv> z5m{ALg&>p3bzpku)=*JRlO)sW-M}cOX=((S&+i6irfAxdAd5xpz^qoW1LG6e7Dc)D zP+)8u6H)Rf`%_@fM3(#wc;Boj%jm#tw?0u-yn)kXbuBtDXA-pbh^`yxxHJr711}%G z-3~o|;r(g)dX0&(b{s2Az~Sh+#{;pMQ)_F3i9?ViuwB>2PwdUWSk8WbK|JGSEO{p| n8_Tjb@b)wQYk!?*{c(K(wSJimSdJ6(00000NkvXXu0mjfih%ky literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..1f858be1cee3f5d8f2b67f55d730e6d3f43e9b42 GIT binary patch literal 2021 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..b51e0b3f4c61ba166b69bd7f32cb23dc8428429e GIT binary patch literal 1965 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exclude.png b/web/pgadmin/misc/static/explain/img/exclude.png new file mode 100644 index 0000000000000000000000000000000000000000..bd62eef6410d9315857d2e6d246770e8b65b8f47 GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47y|-)LR^8|wi}<ymTvVw_QrY1 zLC3?d^*UDhFWLA1|9`)wM`KREbvXQ5A-=(6%9fR9ZhU_6^4^pwS28lLWMw^=HS5>= z_isLZP1<@%wQ`Qjk=K%*nNgG09JqAnY+~Zm($d$dsZT2^E~KQ~e)?Lsd6{J1L`ko# z8QYH^XzhAZSorVPuP+-md|tBT-`~HFYif>6nkJPuNuqp?YIOD56Ib^8`rV6+d^K<0 zzkmPUtXQ!pGFqZ!hGg3swe*g4XK!wIaz5qe_HfFSrwbQu^AC`0S|K@Qk7Uk-*~hPM zEhsq<82I=1?;BI6UhV1m_vg>S@bIm*jgk|0NG?2Of9R!T^@7Cpr%znEwc5~Vm%sly zUEQ5NKC5l*c3rqFx8Q{2nrn7@9?A4<w%>5&&c`3`Z{FOOoV;9Hdxfs<!JM4Ox9?6m zenWfBW$A4XY?hzYUUH^<`Bv54PXhWDq@H_cwegx-ao6F7A05CjWh@Eu3ubV5b|VeM zN%D4g;b^-zwF=1LEbxdd2GSm2>~=ES4#-&V>Eak7aXC5R07H*Y2Gbdx45l?XZ+LiQ zWMmY~)Ws(}c=qt=V{riyAu&Nw;pq&V9$ucOPn<e=Qd>hyv$&ZhB;@K9Q<JS*N=v?e zImpD;=5|bN*|M}_&%~xBFluK@M_UI6S4XqEt8Zx7+`W4C?)K%=xA(7?_c&m$V4z{4 zVq&6Wqh!RTA|NX)Ek1w3j45*_&6>t1bmBw`i*--4qPDWM%7n?><t2V{=CjN{U1V)w zV3-jtUHUai{xs0(swJ)wB`Jv|saDBFsX&Us$iUE0*8qr2Lkumf3@ojTjkFEStPBi} hcbK)IXvob^$xN%ntzp~MJ}aOG22WQ%mvv4FO#q89Jv#sZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension-sm.png b/web/pgadmin/misc/static/explain/img/extension-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..432d2f44231c1f88e787091060efc5125d80ef64 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E0BJDv+cp5$Qv6qzrVk7 zW3&9@vzBik`G5Ho|K-)uTicc2-1GkNGyU0x%oo?3fBedPak1gnHlr`^;(z|izO~Kb z%lm|1zjI$+bN~H2|Mm{mcMpR9{3*J*S>f3^`;Si}e|^pQ`={jETDdE$#Qyy)dv><$ z|KAGswyocQwlbCk`2{mLJiCzw<Zu>vL>2>S4={E+nQaGT<aoL`hDcoQ?f2wsP!M2o z7l{eDQ+~(c|9@BE84^1Kx361bY|Bu`qQb-J62DBxZ_<p5BE`pwna}6wxpa1%>e!Vz zahdU=*X&ESFOpJE*&;e)`qd3*DpaT5u9JDLS%3P((k)@<ZbaLzV+h!Of4=?`KK92q z=3fE@l4^--L`h0wNvc(HQ7VvPFfuSS&^0vDH82b@GO#i+wlXo*HZZj^FqrpFZxxD$ o-29Zxv`UBu152<5plTB<12c$*Q`1A&05vdpy85}Sb4q9e01}k2!2kdN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension.png b/web/pgadmin/misc/static/explain/img/extension.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732 GIT binary patch literal 996 zcmV<A0~`E_P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%`cO<%MQ2zLf_6I6&9|zdd99>-@a*2m!Junh7N)|bRf|-bx|zVboSKha_w(lG z;mc-L4XVVcQjb)R!IoN>UTm6cdTlP+)48aeY_F(+!qvh)fIq$I$ak@QM1Demb2p-y zZNIpg%*U?Z+|0eUmR?Q)@#@yLtA3u9XFhv8mdv0tb~C!Ok)4xckc3Wsa4?*aUD?pH z@afX-<;s|gP-<HecxWLITMn+{ye)Dq{QLL&`11Mo?Dg>A^X%E{;lk+My5`xk<JGC) z(V?J^Pa0qr9%URUZYXJ}aH`|EXsd7=V;MkvKHbcisFznYY9*e@qsi^kq0p+c;k~!# z!?5MPqv5li->#6?p?1NAale3n)0NuDkgb|nMQ$vEwur;)&X(P%klLe(*qwsbn0(Ze z&%lqBg+*3S1ZY?dnutTImr{GNfpyZ2etkM9XCNqTCtr9wihVOAV;iN_u6D(TK#xcf zTn`v!7(bOtw4`b=XCQ>Lht=`it<|(#mtSF?W<QQcm$;T>m1BZ;G0*SUx8%WGt7&4B zV3D+tb8RIwgF3Luu#bN^7G4v==*yVRp-_@kjmeoSdoaG!zSzWv!K`UHUKC!MVuZSj zaIAJVdpAyF9vxyClh&g+jY8GGe$u;klYuouT@*iVD?w)>Y;7EsekVC?DRR1gZ_tQZ zyKv99ZOyY~z@}84hBK{_JHn(!l6fLVbTnhFZfMSfV$6Lul0qhGC2*Z?NP<TvhBL~q zUB|0c#ivccpg)Ro98G#WT*`P>$a6}(W;2>aI;l}Wz+t|fIeljlScFSfreaXWZ%f2# zMZ#t~zg?k^OOAUphI1*4cr3V}Qns8&igY1@Y#D@Y7H?b$T8UCtsbn_2S%i2!rk!)h z!>EaMCcvamyR?(W!KK8$qF<3+9BCaAUJ)8<9X6LmEss1DV->ZTL3e2=8EP9)hfaum zLy>wXERsEdsDEo(3zmE$ex`jsyImG&7=LOOfol~TcO*%INEmJ%7i}B|YRn1%0004W zQchC<K<3zH00001VoOIv0Eh)0NB{r;32;bRa{vGf6951U69E94oEQKA00(qQO+^RW z0~-xG4!&HBF8}}lR!KxbR2b7^U?3j2xS;VvLXbtwTz~>0W=QhVA)yH_FkL{}1;huk zpaKCQKz@=7s`{i97i0@vl2TS8w1C7?R&G7y;)1Nm<<OZkC{A-h<6}A<CjbDaP8qDe SR_4e60000<MNUMnLSTaX-^L37 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extensions.png b/web/pgadmin/misc/static/explain/img/extensions.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5 GIT binary patch literal 1017 zcmV<V0|xwwP)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%_fSk!MS^xZ(#^N3p?R&Od+_Yu$ibj%T^6RorB#bmn!1_5x}2JiUH9|m=i$p{ zRt>7esZx(rkHMB&m|kp}YkF-i+S9qHoNTYCfx^|oK7c>H>Bx7neMEjjfO9vZnQgzg znaszo-`vc-ww7K_0rBeAwyS=gm1jPCJeJI$Gj=n&vyq*XV~~VSeQ+?GkzLu)v+(KC z?&Zpui%@D?5_o7K5L*te<Gd|$E&TiU`}p$t_U!fW;PdR+>*2!a-MZ%4vg6gM;L)L= zk53w479M3BDQ+lfsBo&|xoE3!8)F$jd_LXGn5dUmHEJcE$)m~b(xK3*v*EqB=fkk& zzN6u@o!_pI*P(X7g>k=tf76xP$dIj?SVe9ugSLpn>&}+lsF2#DiP)Wj)|h<Mlh449 zm4!uCPy}dL4Vs8UtCv!Hv4M5cjedPPC}$ujZ6{xNJBocXBx4(;)vk8Mhd_@=5nK-# zWf(t|O0=YEF=rrzvxn93+^yBLT$f*Ao@PIeN0+#kWR+urcQMcJ*SF-sT&rnflVFjw zkaKM%G=n;@$*_-qITl_M!syGG&7n||RE^1*D|;}$)4tfmhrz6AIbIZAnqq{yi*T%V zHhVWtV;&u18I#tdIE_NpzkbrYc9VfMLtPX<ZYx1&B5Z9Om3}8VZ7FiPes9o-TDx%1 zw{6X{Wx%FXorW{5k~_krMv{3VMsze|t!`+}gJR5mHj+XnY9(-;Zb*VhCx$c1uU*Hh zRmG=Gz@R^havV*1JY33nR>*Toyk;|+MLMZbK)_+XojHAH5m<yvR;FT5#&1i+YDL0k zJHK6_k4uhwGlp|1i+C)!pi;J+M~ZYIf@~RtZ5D4_30jF#R;gq*y;+2KJ*J&=$it|K zbtb^1PrI~}#=)h;zM@}|T^wm05?&D+Y8^J0MJ<m!6k`>&nL&4HC>d%SP=`*4d_$3X zCoGaZfT(|KS__tZB7UZQKD%8OXc&KL7J+LO8+Rm0f=C!{9T#mJ7UDFE00001bW%=J z06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru+XEXB z6Cp(Rbcp}}0B%V{K~xyiU68R2z#t3+nS(tt!3~hY^vGg42FL=`EENNm0{M!6-y1;) zQxFazvL_cK*b<_okFg0d8Hc#V=Eh`)h+yZmplehnlNZEdtgQ@hX0CNeIWEpxw!oyN ndc~tsp9TlidOzOC&-)*|KH)3pD2ngr00000NkvXXu0mjf<KNUz literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable-sm.png b/web/pgadmin/misc/static/explain/img/exttable-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..acd43cb8abab6ef38daf34ff6d7544153a11dacf GIT binary patch literal 612 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47`X#{LR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)^XY$8$A0G@_?f)(TiB-0o~u9DE`4h_ z@3s2Om(8dDdI7mh-fGNz8JxJ$(RuCl>$mUSyLbQo{YQ@;J%0Rn>9T9)mKA9e*Bv-; z!q9k*y7s}c^63vAJOIkOd8|>@*q@f(clYkyWy_XDM0Trbo^<nAscUdhS#3sp`^5F@ z*S~u8DlvJNy7pxi^{qR09)J1r<?Gk4&!4|-WV%sNW#!y?Ya^o8sA?W7EL!yO<Hxse z-}X<~s-}6=(71d4{Dn`SK5cATs;+%VU9<bdiL;%Z6I)tVJ$drv&6_t59=vw<+ErTC zQw{Rh4~>~Gc%JJ_00swRNswPKgTu2MX+REVfk$L9koEv$x0Bg+K*j`57sn8Z%gG4} zOa@Af9Sp+8+}hIC?Ck2|<}MBG)BEEc0z4vIL{>Gq^Qb83DJpS_PM9=p;?&9E0U<$c zTq{<rTA7`ZmHE2Bfwko87hay;9$%lc3z#+)6+IK17IrPoEP&B6+Pa$ET|Heqd_}|T z-R;Y#Z{6O%UOwc2y~2g=!)h89Dk9JL?rkX8V67z4`B96(W2)e}i60vRfNoPQag8WR zNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTd cHGouG8JIydoSGiG2B?9-)78&qol`;+0LVQH?EnA( literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable.png b/web/pgadmin/misc/static/explain/img/exttable.png new file mode 100644 index 0000000000000000000000000000000000000000..5d84035feea62d53d457481178b1bcbe9622f856 GIT binary patch literal 793 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47;6K3LR^7d#i`GGFZ`c${`aEG zUw7Sjd-49u`;VVLefIp>vuC#+K3#L}dGf{=db3}2pa0)_=3m{3Kc$C%<?Q>BxZ_*c zrqAAMJ~%9YXTIQ#?wnU@GhViy`J27(hvTw$W((iw&U_Y~)1HyF{qEhn_wL=hfB*i2 z2M-=TeE8_mqsNaQ8yXiV>iW%}zd>1TV^GL$BjYL^{S(WU9oVt+prXnmSNFZkm#=*C z<jL~o%k>TF^o@>PyZ-vst5*{zPLflcU|_QU>a|B#uU=JF?bJ2cziipY_3PKae*OB& zm8%-sEqaEB)ikG?m>;=w=lPpAZ{EIr`|{<>zP<^HDjPJkuS}Y>_5J(zA3l8e^y$;P zckfoNT)BGn>N#`fDXPqIbUAEeo3EjBs<&_JrcIlkKYzY=?-6CSwcft_U%!6i?2@ga zbAH+K$Dcoc{`&RnzI`WD)Hj5LAKkcd)7Gt9lT#YiwN7;R-um|K+wv9LmDM(Tcy0Rl z@#D5_+u{=nRW-JDc3)AL{8UY|HzVudq)BroPg$ri@$mwIO;dmoz*rLG7tG-B>_!@p z!&%@FSq!8-z}W3%wjGdh+0(@_MB;LCLV^n;4-Zd|&l#OHId5d<%!#>Uvqyo^u8z@B zF;Otku#nSp1DBm9qhscRhMqMtE)H>yfu51Bp}w)6&cZqimabjQ@@VyoS1+4cMR<97 zd#?KUoIRtfbCAhvS=cqRZDrs1`uxr%FfOPQ4>vF8_xIM%-_X$2-@kPI{CbCkfC7#P z2U8Or8zmzxD>XAS4xIy%;`1lWcrs_sq*>GW#5zu&ICF}R^VG?+r}Y`QMZ`qYkF!mE zGG*G-@CFvG)vNY8H+eN(zQmoCbx`Y7z#e{vFBY0Te&TE7f!<Rsag8WRNi0dVN-jzT zQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTdHGouG8JIyd UoSGiG2B?9-)78&qol`;+0Q{<O$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttables.png b/web/pgadmin/misc/static/explain/img/exttables.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dfbd454ed33727bd1deeb87c62f8671f6a5a03 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47^MPyLR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)(1uT&ufDx|_ipp)e^tkR=O6f)yz^Vw zrq7<MKiDpPYdG(<`plR2?%iuX{nra9vgEDdjF%cSU*5le-z{*Hjoqv(SFS&L^yu;9 z$BCh54YV)SY`ps5!GohmFPT|vP}AIAUOws6@q1>vXAHE?^>wU&`SRt%hYy!6TNV*D zT}|t>v;9UL?W?Amt7goYwSN8jSFc`8IQ7}h=Aef5HBHT(=Pz7){rdI(-PetE&Kqf+ zTC?J?x9>_dt@Dk|J3fB=`1bAF+~nQb+SeRSH>_B(;_1_;Rn;?8HFg`BEWUQ_zJ=bg zri$H9o;-Q;=FOu=PwX9+YwPW<2KnxXa>IqjgMEvDp~F}b<QL4~@a#q!ki%Kv5m^kR zJ;2!QWVRiUvDwqbF+}2W?0HwQLk<G27xhdW8XmB4zY~jTVks}b`QPk?8Z+O@ht}mE zxDUR+@ZDiy$V$_wu1ha@gBJAuXUmw$IQdLNWLm+2wv7?FW$l-rva#qG$_eeUt7l;6 zYfsQPQ#3I{XWjwDPG7CLC)J97I!!#j(8XtG(AulgXTzi?C<q+hI5%(o`R%TodS@Ig zFq!9*{+X5YhEDkFv(xUs<#&JSY%y0q+H23fcl??hCZB62%C0l7Vc_x-dugW}eiG<> z)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!XjU}|MxU@=ow4n;$5eoAIq iB}9XPC0GMUwUvPxM8m1+p=*E|7(8A5T-G@yGywoZHZsuw literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/js/snap.svg-min.js b/web/pgadmin/misc/static/explain/js/snap.svg-min.js new file mode 100644 index 0000000..6567d19 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg-min.js @@ -0,0 +1,21 @@ +// Snap.svg 0.4.1 +// +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// build: 2015-04-13 + +!function(a){var b,c,d="0.4.2",e="hasOwnProperty",f=/[\.\/]/,g=/\s*,\s*/,h="*",i=function(a,b){return a-b},j={n:{}},k=function(){for(var a=0,b=this.length;b>a;a++)if("undefined"!=typeof this[a])return this[a]},l=function(){for(var a=this.length;--a;)if("undefined"!=typeof this[a])return this[a]},m=function(a,d){a=String(a);var e,f=c,g=Array.prototype.slice.call(arguments,2),h=m.listeners(a),j=0,n=[],o={},p=[],q=b;p.firstDefined=k,p.lastDefined=l,b=a,c=0;for(var r=0,s=h.length;s>r;r++)"zIndex"in h[r]&&(n.push(h[r].zIndex),h[r].zIndex<0&&(o[h[r].zIndex]=h[r]));for(n.sort(i);n[j]<0;)if(e=o[n[j++]],p.push(e.apply(d,g)),c)return c=f,p;for(r=0;s>r;r++)if(e=h[r],"zIndex"in e)if(e.zIndex==n[j]){if(p.push(e.apply(d,g)),c)break;do if(j++,e=o[n[j]],e&&p.push(e.apply(d,g)),c)break;while(e)}else o[e.zIndex]=e;else if(p.push(e.apply(d,g)),c)break;return c=f,b=q,p};m._events=j,m.listeners=function(a){var b,c,d,e,g,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,g=m.length;g>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[h]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},m.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(g),d=0,e=c.length;e>d;d++)!function(a){for(var c,d=a.split(f),e=j,g=0,h=d.length;h>g;g++)e=e.n,e=e.hasOwnProperty(d[g])&&e[d[g]]||(e[d[g]]={n:{}});for(e.f=e.f||[],g=0,h=e.f.length;h>g;g++)if(e.f[g]==b){c=!0;break}!c&&e.f.push(b)}(c[d]);return function(a){+a==+a&&(b.zIndex=+a)}},m.f=function(a){var b=[].slice.call(arguments,1);return function(){m.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},m.stop=function(){c=1},m.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},m.nts=function(){return b.split(f)},m.off=m.unbind=function(a,b){if(!a)return void(m._events=j={n:{}});var c=a.split(g);if(c.length>1)for(var d=0,i=c.length;i>d;d++)m.off(c[d],b);else{c=a.split(f);var k,l,n,d,i,o,p,q=[j];for(d=0,i=c.length;i>d;d++)for(o=0;o<q.length;o+=n.length-2){if(n=[o,1],k=q[o].n,c[d]!=h)k[c[d]]&&n.push(k[c[d]]);else for(l in k)k[e](l)&&n.push(k[l]);q.splice.apply(q,n)}for(d=0,i=q.length;i>d;d++)for(k=q[d];k.n;){if(b){if(k.f){for(o=0,p=k.f.length;p>o;o++)if(k.f[o]==b){k.f.splice(o,1);break}!k.f.length&&delete k.f}for(l in k.n)if(k.n[e](l)&&k.n[l].f){var r=k.n[l].f;for(o=0,p=r.length;p>o;o++)if(r[o]==b){r.splice(o,1);break}!r.length&&delete k.n[l].f}}else{delete k.f;for(l in k.n)k.n[e](l)&&k.n[l].f&&delete k.n[l].f}k=k.n}}},m.once=function(a,b){var c=function(){return m.unbind(a,c),b.apply(this,arguments)};return m.on(a,c)},m.version=d,m.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=m:"function"==typeof define&&define.amd?define("eve",[],function(){return m}):a.eve=m}(this),function(a,b){if("function"==typeof define&&define.amd)define(["eve"],function(c){return b(a,c)});else if("undefined"!=typeof exports){var c=require("eve");module.exports=b(a,c)}else b(a,a.eve)}(window||this,function(a,b){var c=function(b){var c={},d=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},e=Array.isArray||function(a){return a instanceof Array||"[object Array]"==Object.prototype.toString.call(a)},f=0,g="M"+(+new Date).toString(36),h=function(){return g+(f++).toString(36)},i=Date.now||function(){return+new Date},j=function(a){var b=this;if(null==a)return b.s;var c=b.s-a;b.b+=b.dur*c,b.B+=b.dur*c,b.s=a},k=function(a){var b=this;return null==a?b.spd:void(b.spd=a)},l=function(a){var b=this;return null==a?b.dur:(b.s=b.s*a/b.dur,void(b.dur=a))},m=function(){var a=this;delete c[a.id],a.update(),b("mina.stop."+a.id,a)},n=function(){var a=this;a.pdif||(delete c[a.id],a.update(),a.pdif=a.get()-a.b)},o=function(){var a=this;a.pdif&&(a.b=a.get()-a.pdif,delete a.pdif,c[a.id]=a)},p=function(){var a,b=this;if(e(b.start)){a=[];for(var c=0,d=b.start.length;d>c;c++)a[c]=+b.start[c]+(b.end[c]-b.start[c])*b.easing(b.s)}else a=+b.start+(b.end-b.start)*b.easing(b.s);b.set(a)},q=function(){var a=0;for(var e in c)if(c.hasOwnProperty(e)){var f=c[e],g=f.get();a++,f.s=(g-f.b)/(f.dur/f.spd),f.s>=1&&(delete c[e],f.s=1,a--,function(a){setTimeout(function(){b("mina.finish."+a.id,a)})}(f)),f.update()}a&&d(q)},r=function(a,b,e,f,g,i,s){var t={id:h(),start:a,end:b,b:e,s:0,dur:f-e,spd:1,get:g,set:i,easing:s||r.linear,status:j,speed:k,duration:l,stop:m,pause:n,resume:o,update:p};c[t.id]=t;var u,v=0;for(u in c)if(c.hasOwnProperty(u)&&(v++,2==v))break;return 1==v&&d(q),t};return r.time=i,r.getById=function(a){return c[a]||null},r.linear=function(a){return a},r.easeout=function(a){return Math.pow(a,1.7)},r.easein=function(a){return Math.pow(a,.48)},r.easeinout=function(a){if(1==a)return 1;if(0==a)return 0;var b=.48-a/1.04,c=Math.sqrt(.1734+b*b),d=c-b,e=Math.pow(Math.abs(d),1/3)*(0>d?-1:1),f=-c-b,g=Math.pow(Math.abs(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},r.backin=function(a){if(1==a)return 1;var b=1.70158;return a*a*((b+1)*a-b)},r.backout=function(a){if(0==a)return 0;a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},r.elastic=function(a){return a==!!a?a:Math.pow(2,-10*a)*Math.sin(2*(a-.075)*Math.PI/.3)+1},r.bounce=function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b},a.mina=r,r}("undefined"==typeof b?function(){}:b),d=function(a){function c(a,b){if(a){if(a.nodeType)return w(a);if(e(a,"array")&&c.set)return c.set.apply(c,a);if(a instanceof s)return a;if(null==b)return a=y.doc.querySelector(String(a)),w(a)}return a=null==a?"100%":a,b=null==b?"100%":b,new v(a,b)}function d(a,b){if(b){if("#text"==a&&(a=y.doc.createTextNode(b.text||b["#text"]||"")),"#comment"==a&&(a=y.doc.createComment(b.text||b["#text"]||"")),"string"==typeof a&&(a=d(a)),"string"==typeof b)return 1==a.nodeType?"xlink:"==b.substring(0,6)?a.getAttributeNS(T,b.substring(6)):"xml:"==b.substring(0,4)?a.getAttributeNS(U,b.substring(4)):a.getAttribute(b):"text"==b?a.nodeValue:null;if(1==a.nodeType){for(var c in b)if(b[z](c)){var e=A(b[c]);e?"xlink:"==c.substring(0,6)?a.setAttributeNS(T,c.substring(6),e):"xml:"==c.substring(0,4)?a.setAttributeNS(U,c.substring(4),e):a.setAttribute(c,e):a.removeAttribute(c)}}else"text"in b&&(a.nodeValue=b.text)}else a=y.doc.createElementNS(U,a);return a}function e(a,b){return b=A.prototype.toLowerCase.call(b),"finite"==b?isFinite(a):"array"==b&&(a instanceof Array||Array.isArray&&Array.isArray(a))?!0:"null"==b&&null===a||b==typeof a&&null!==a||"object"==b&&a===Object(a)||J.call(a).slice(8,-1).toLowerCase()==b}function f(a){if("function"==typeof a||Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[z](c)&&(b[c]=f(a[c]));return b}function h(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function i(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),g=d.cache=d.cache||{},i=d.count=d.count||[];return g[z](f)?(h(i,f),c?c(g[f]):g[f]):(i.length>=1e3&&delete g[i.shift()],i.push(f),g[f]=a.apply(b,e),c?c(g[f]):g[f])}return d}function j(a,b,c,d,e,f){if(null==e){var g=a-c,h=b-d;return g||h?(180+180*D.atan2(-h,-g)/H+360)%360:0}return j(a,b,e,f)-j(c,d,e,f)}function k(a){return a%360*H/180}function l(a){return 180*a/H%360}function m(a){var b=[];return a=a.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g,function(a,c,d){return d=d.split(/\s*,\s*|\s+/),"rotate"==c&&1==d.length&&d.push(0,0),"scale"==c&&(d.length>2?d=d.slice(0,2):2==d.length&&d.push(0,0),1==d.length&&d.push(d[0],0,0)),b.push("skewX"==c?["m",1,0,D.tan(k(d[0])),1,0,0]:"skewY"==c?["m",1,D.tan(k(d[0])),0,1,0,0]:[c.charAt(0)].concat(d)),a}),b}function n(a,b){var d=ab(a),e=new c.Matrix;if(d)for(var f=0,g=d.length;g>f;f++){var h,i,j,k,l,m=d[f],n=m.length,o=A(m[0]).toLowerCase(),p=m[0]!=o,q=p?e.invert():0;"t"==o&&2==n?e.translate(m[1],0):"t"==o&&3==n?p?(h=q.x(0,0),i=q.y(0,0),j=q.x(m[1],m[2]),k=q.y(m[1],m[2]),e.translate(j-h,k-i)):e.translate(m[1],m[2]):"r"==o?2==n?(l=l||b,e.rotate(m[1],l.x+l.width/2,l.y+l.height/2)):4==n&&(p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.rotate(m[1],j,k)):e.rotate(m[1],m[2],m[3])):"s"==o?2==n||3==n?(l=l||b,e.scale(m[1],m[n-1],l.x+l.width/2,l.y+l.height/2)):4==n?p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.scale(m[1],m[1],j,k)):e.scale(m[1],m[1],m[2],m[3]):5==n&&(p?(j=q.x(m[3],m[4]),k=q.y(m[3],m[4]),e.scale(m[1],m[2],j,k)):e.scale(m[1],m[2],m[3],m[4])):"m"==o&&7==n&&e.add(m[1],m[2],m[3],m[4],m[5],m[6])}return e}function o(a){var b=a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||a.node.parentNode&&w(a.node.parentNode)||c.select("svg")||c(0,0),d=b.select("defs"),e=null==d?!1:d.node;return e||(e=u("defs",b.node).node),e}function p(a){return a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||c.select("svg")}function q(a,b,c){function e(a){if(null==a)return I;if(a==+a)return a;d(j,{width:a});try{return j.getBBox().width}catch(b){return 0}}function f(a){if(null==a)return I;if(a==+a)return a;d(j,{height:a});try{return j.getBBox().height}catch(b){return 0}}function g(d,e){null==b?i[d]=e(a.attr(d)||0):d==b&&(i=e(null==c?a.attr(d)||0:c))}var h=p(a).node,i={},j=h.querySelector(".svg---mgr");switch(j||(j=d("rect"),d(j,{x:-9e9,y:-9e9,width:10,height:10,"class":"svg---mgr",fill:"none"}),h.appendChild(j)),a.type){case"rect":g("rx",e),g("ry",f);case"image":g("width",e),g("height",f);case"text":g("x",e),g("y",f);break;case"circle":g("cx",e),g("cy",f),g("r",e);break;case"ellipse":g("cx",e),g("cy",f),g("rx",e),g("ry",f);break;case"line":g("x1",e),g("x2",e),g("y1",f),g("y2",f);break;case"marker":g("refX",e),g("markerWidth",e),g("refY",f),g("markerHeight",f);break;case"radialGradient":g("fx",e),g("fy",f);break;case"tspan":g("dx",e),g("dy",f);break;default:g(b,e)}return h.removeChild(j),i}function r(a){e(a,"array")||(a=Array.prototype.slice.call(arguments,0));for(var b=0,c=0,d=this.node;this[b];)delete this[b++];for(b=0;b<a.length;b++)"set"==a[b].type?a[b].forEach(function(a){d.appendChild(a.node)}):d.appendChild(a[b].node);var f=d.childNodes;for(b=0;b<f.length;b++)this[c++]=w(f[b]);return this}function s(a){if(a.snap in V)return V[a.snap];var b;try{b=a.ownerSVGElement}catch(c){}this.node=a,b&&(this.paper=new v(b)),this.type=a.tagName||a.nodeName;var d=this.id=S(this);if(this.anims={},this._={transform:[]},a.snap=d,V[d]=this,"g"==this.type&&(this.add=r),this.type in{g:1,mask:1,pattern:1,symbol:1})for(var e in v.prototype)v.prototype[z](e)&&(this[e]=v.prototype[e])}function t(a){this.node=a}function u(a,b){var c=d(a);b.appendChild(c);var e=w(c);return e}function v(a,b){var c,e,f,g=v.prototype;if(a&&"svg"==a.tagName){if(a.snap in V)return V[a.snap];var h=a.ownerDocument;c=new s(a),e=a.getElementsByTagName("desc")[0],f=a.getElementsByTagName("defs")[0],e||(e=d("desc"),e.appendChild(h.createTextNode("Created with Snap")),c.node.appendChild(e)),f||(f=d("defs"),c.node.appendChild(f)),c.defs=f;for(var i in g)g[z](i)&&(c[i]=g[i]);c.paper=c.root=c}else c=u("svg",y.doc.body),d(c.node,{height:b,version:1.1,width:a,xmlns:U});return c}function w(a){return a?a instanceof s||a instanceof t?a:a.tagName&&"svg"==a.tagName.toLowerCase()?new v(a):a.tagName&&"object"==a.tagName.toLowerCase()&&"image/svg+xml"==a.type?new v(a.contentDocument.getElementsByTagName("svg")[0]):new s(a):a}function x(a,b){for(var c=0,d=a.length;d>c;c++){var e={type:a[c].type,attr:a[c].attr()},f=a[c].children();b.push(e),f.length&&x(f,e.childNodes=[])}}c.version="0.4.0",c.toString=function(){return"Snap v"+this.version},c._={};var y={win:a.window,doc:a.window.document};c._.glob=y;{var z="hasOwnProperty",A=String,B=parseFloat,C=parseInt,D=Math,E=D.max,F=D.min,G=D.abs,H=(D.pow,D.PI),I=(D.round,""),J=Object.prototype.toString,K=/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,L=(c._.separator=/[,\s]+/,/[\s]*,[\s]*/),M={hs:1,rg:1},N=/([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,O=/([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,P=/(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/gi,Q=0,R="S"+(+new Date).toString(36),S=function(a){return(a&&a.type?a.type:I)+R+(Q++).toString(36)},T="http://www.w3.org/1999/xlink",U="http://www.w3.org/2000/svg",V={};c.url=function(a){return"url('#"+a+"')"}}c._.$=d,c._.id=S,c.format=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return A(b).replace(a,function(a,b){return c(a,b,d)})}}(),c._.clone=f,c._.cacher=i,c.rad=k,c.deg=l,c.sin=function(a){return D.sin(c.rad(a))},c.tan=function(a){return D.tan(c.rad(a))},c.cos=function(a){return D.cos(c.rad(a))},c.asin=function(a){return c.deg(D.asin(a))},c.acos=function(a){return c.deg(D.acos(a))},c.atan=function(a){return c.deg(D.atan(a))},c.atan2=function(a){return c.deg(D.atan2(a))},c.angle=j,c.len=function(a,b,d,e){return Math.sqrt(c.len2(a,b,d,e))},c.len2=function(a,b,c,d){return(a-c)*(a-c)+(b-d)*(b-d)},c.closestPoint=function(a,b,c){function d(a){var d=a.x-b,e=a.y-c;return d*d+e*e}for(var e,f,g,h,i=a.node,j=i.getTotalLength(),k=j/i.pathSegList.numberOfItems*.125,l=1/0,m=0;j>=m;m+=k)(h=d(g=i.getPointAtLength(m)))<l&&(e=g,f=m,l=h);for(k*=.5;k>.5;){var n,o,p,q,r,s;(p=f-k)>=0&&(r=d(n=i.getPointAtLength(p)))<l?(e=n,f=p,l=r):(q=f+k)<=j&&(s=d(o=i.getPointAtLength(q)))<l?(e=o,f=q,l=s):k*=.5}return e={x:e.x,y:e.y,length:f,distance:Math.sqrt(l)}},c.is=e,c.snapTo=function(a,b,c){if(c=e(c,"finite")?c:10,e(a,"array")){for(var d=a.length;d--;)if(G(a[d]-b)<=c)return a[d]}else{a=+a;var f=b%a;if(c>f)return b-f;if(f>a-c)return b-f+a}return b},c.getRGB=i(function(a){if(!a||(a=A(a)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};if("none"==a)return{r:-1,g:-1,b:-1,hex:"none",toString:Z};if(!(M[z](a.toLowerCase().substring(0,2))||"#"==a.charAt())&&(a=W(a)),!a)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};var b,d,f,g,h,i,j=a.match(K);return j?(j[2]&&(f=C(j[2].substring(5),16),d=C(j[2].substring(3,5),16),b=C(j[2].substring(1,3),16)),j[3]&&(f=C((h=j[3].charAt(3))+h,16),d=C((h=j[3].charAt(2))+h,16),b=C((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=B(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),f=B(i[2]),"%"==i[2].slice(-1)&&(f*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100)),j[5]?(i=j[5].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsb2rgb(b,d,f,g)):j[6]?(i=j[6].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsl2rgb(b,d,f,g)):(b=F(D.round(b),255),d=F(D.round(d),255),f=F(D.round(f),255),g=F(E(g,0),1),j={r:b,g:d,b:f,toString:Z},j.hex="#"+(16777216|f|d<<8|b<<16).toString(16).slice(1),j.opacity=e(g,"finite")?g:1,j)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z}},c),c.hsb=i(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=i(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=i(function(a,b,c,d){if(e(d,"finite")){var f=D.round;return"rgba("+[f(a),f(b),f(c),+d.toFixed(2)]+")"}return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)});var W=function(a){var b=y.doc.getElementsByTagName("head")[0]||y.doc.getElementsByTagName("svg")[0],c="rgb(255, 0, 0)";return(W=i(function(a){if("red"==a.toLowerCase())return c;b.style.color=c,b.style.color=a;var d=y.doc.defaultView.getComputedStyle(b,I).getPropertyValue("color");return d==c?null:d}))(a)},X=function(){return"hsb("+[this.h,this.s,this.b]+")"},Y=function(){return"hsl("+[this.h,this.s,this.l]+")"},Z=function(){return 1==this.opacity||null==this.opacity?this.hex:"rgba("+[this.r,this.g,this.b,this.opacity]+")"},$=function(a,b,d){if(null==b&&e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&e(a,string)){var f=c.getRGB(a);a=f.r,b=f.g,d=f.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},_=function(a,b,d,f){a=D.round(255*a),b=D.round(255*b),d=D.round(255*d);var g={r:a,g:b,b:d,opacity:e(f,"finite")?f:1,hex:c.rgb(a,b,d),toString:Z};return e(f,"finite")&&(g.opacity=f),g};c.color=function(a){var b;return e(a,"object")&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):e(a,"object")&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):(e(a,"string")&&(a=c.getRGB(a)),e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&!("error"in a)?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:"none"},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1,a.error=1)),a.toString=Z,a},c.hsb2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,d=a.o,a=a.h),a*=360;var f,g,h,i,j;return a=a%360/60,j=c*b,i=j*(1-G(a%2-1)),f=g=h=c-j,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.hsl2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var f,g,h,i,j;return a=a%360/60,j=2*b*(.5>c?c:1-c),i=j*(1-G(a%2-1)),f=g=h=c-j/2,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.rgb2hsb=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=E(a,b,c),g=f-F(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:X}},c.rgb2hsl=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=E(a,b,c),h=F(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:Y}},c.parsePathString=function(a){if(!a)return null;var b=c.path(a);if(b.arr)return c.path.clone(b.arr);var d={a:7,c:6,o:2,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,u:3,z:0},f=[];return e(a,"array")&&e(a[0],"array")&&(f=c.path.clone(a)),f.length||A(a).replace(N,function(a,b,c){var e=[],g=b.toLowerCase();if(c.replace(P,function(a,b){b&&e.push(+b)}),"m"==g&&e.length>2&&(f.push([b].concat(e.splice(0,2))),g="l",b="m"==b?"l":"L"),"o"==g&&1==e.length&&f.push([b,e[0]]),"r"==g)f.push([b].concat(e));else for(;e.length>=d[g]&&(f.push([b].concat(e.splice(0,d[g]))),d[g]););}),f.toString=c.path.toString,b.arr=c.path.clone(f),f};var ab=c.parseTransformString=function(a){if(!a)return null;var b=[];return e(a,"array")&&e(a[0],"array")&&(b=c.path.clone(a)),b.length||A(a).replace(O,function(a,c,d){{var e=[];c.toLowerCase()}d.replace(P,function(a,b){b&&e.push(+b)}),b.push([c].concat(e))}),b.toString=c.path.toString,b};c._.svgTransform2string=m,c._.rgTransform=/^[a-z][\s]*-?\.?\d/i,c._.transform2matrix=n,c._unit2px=q;y.doc.contains||y.doc.compareDocumentPosition?function(a,b){var c=9==a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a==d||!(!d||1!=d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b;)if(b=b.parentNode,b==a)return!0;return!1};c._.getSomeDefs=o,c._.getSomeSVG=p,c.select=function(a){return a=A(a).replace(/([^\\]):/g,"$1\\:"),w(y.doc.querySelector(a))},c.selectAll=function(a){for(var b=y.doc.querySelectorAll(a),d=(c.set||Array)(),e=0;e<b.length;e++)d.push(w(b[e]));return d},setInterval(function(){for(var a in V)if(V[z](a)){var b=V[a],c=b.node;("svg"!=b.type&&!c.ownerSVGElement||"svg"==b.type&&(!c.parentNode||"ownerSVGElement"in c.parentNode&&!c.ownerSVGElement))&&delete V[a]}},1e4),s.prototype.attr=function(a,c){var d=this,f=d.node;if(!a){if(1!=f.nodeType)return{text:f.nodeValue};for(var g=f.attributes,h={},i=0,j=g.length;j>i;i++)h[g[i].nodeName]=g[i].nodeValue;return h}if(e(a,"string")){if(!(arguments.length>1))return b("snap.util.getattr."+a,d).firstDefined();var k={};k[a]=c,a=k}for(var l in a)a[z](l)&&b("snap.util.attr."+l,d,a[l]);return d},c.parse=function(a){var b=y.doc.createDocumentFragment(),c=!0,d=y.doc.createElement("div");if(a=A(a),a.match(/^\s*<\s*svg(?:\s|>)/)||(a="<svg>"+a+"</svg>",c=!1),d.innerHTML=a,a=d.getElementsByTagName("svg")[0])if(c)b=a;else for(;a.firstChild;)b.appendChild(a.firstChild);return new t(b)},c.fragment=function(){for(var a=Array.prototype.slice.call(arguments,0),b=y.doc.createDocumentFragment(),d=0,e=a.length;e>d;d++){var f=a[d];f.node&&f.node.nodeType&&b.appendChild(f.node),f.nodeType&&b.appendChild(f),"string"==typeof f&&b.appendChild(c.parse(f).node)}return new t(b)},c._.make=u,c._.wrap=w,v.prototype.el=function(a,b){var c=u(a,this.node);return b&&c.attr(b),c},s.prototype.children=function(){for(var a=[],b=this.node.childNodes,d=0,e=b.length;e>d;d++)a[d]=c(b[d]);return a},s.prototype.toJSON=function(){var a=[];return x([this],a),a[0]},b.on("snap.util.getattr",function(){var a=b.nt();a=a.substring(a.lastIndexOf(".")+1);var c=a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});return bb[z](c)?this.node.ownerDocument.defaultView.getComputedStyle(this.node,null).getPropertyValue(c):d(this.node,a)});var bb={"alignment-baseline":0,"baseline-shift":0,clip:0,"clip-path":0,"clip-rule":0,color:0,"color-interpolation":0,"color-interpolation-filters":0,"color-profile":0,"color-rendering":0,cursor:0,direction:0,display:0,"dominant-baseline":0,"enable-background":0,fill:0,"fill-opacity":0,"fill-rule":0,filter:0,"flood-color":0,"flood-opacity":0,font:0,"font-family":0,"font-size":0,"font-size-adjust":0,"font-stretch":0,"font-style":0,"font-variant":0,"font-weight":0,"glyph-orientation-horizontal":0,"glyph-orientation-vertical":0,"image-rendering":0,kerning:0,"letter-spacing":0,"lighting-color":0,marker:0,"marker-end":0,"marker-mid":0,"marker-start":0,mask:0,opacity:0,overflow:0,"pointer-events":0,"shape-rendering":0,"stop-color":0,"stop-opacity":0,stroke:0,"stroke-dasharray":0,"stroke-dashoffset":0,"stroke-linecap":0,"stroke-linejoin":0,"stroke-miterlimit":0,"stroke-opacity":0,"stroke-width":0,"text-anchor":0,"text-decoration":0,"text-rendering":0,"unicode-bidi":0,visibility:0,"word-spacing":0,"writing-mode":0};b.on("snap.util.attr",function(a){var c=b.nt(),e={};c=c.substring(c.lastIndexOf(".")+1),e[c]=a;var f=c.replace(/-(\w)/gi,function(a,b){return b.toUpperCase()}),g=c.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});bb[z](g)?this.node.style[f]=null==a?I:a:d(this.node,e)}),function(){}(v.prototype),c.ajax=function(a,c,d,f){var g=new XMLHttpRequest,h=S();if(g){if(e(c,"function"))f=d,d=c,c=null;else if(e(c,"object")){var i=[];for(var j in c)c.hasOwnProperty(j)&&i.push(encodeURIComponent(j)+"="+encodeURIComponent(c[j]));c=i.join("&")}return g.open(c?"POST":"GET",a,!0),c&&(g.setRequestHeader("X-Requested-With","XMLHttpRequest"),g.setRequestHeader("Content-type","application/x-www-form-urlencoded")),d&&(b.once("snap.ajax."+h+".0",d),b.once("snap.ajax."+h+".200",d),b.once("snap.ajax."+h+".304",d)),g.onreadystatechange=function(){4==g.readyState&&b("snap.ajax."+h+"."+g.status,f,g)},4==g.readyState?g:(g.send(c),g)}},c.load=function(a,b,d){c.ajax(a,function(a){var e=c.parse(a.responseText);d?b.call(d,e):b(e)})};var cb=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,h=e.clientLeft||d.clientLeft||0,i=b.top+(g.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(g.win.pageXOffset||e.scrollLeft||d.scrollLeft)-h;return{y:i,x:j}};return c.getElementByPoint=function(a,b){var c=this,d=(c.canvas,y.doc.elementFromPoint(a,b));if(y.win.opera&&"svg"==d.tagName){var e=cb(d),f=d.createSVGRect();f.x=a-e.x,f.y=b-e.y,f.width=f.height=1;var g=d.getIntersectionList(f,null);g.length&&(d=g[g.length-1])}return d?w(d):null},c.plugin=function(a){a(c,s,v,y,t)},y.win.Snap=c,c}(a||this);return d.plugin(function(d,e,f,g,h){function i(a,b){if(null==b){var c=!0;if(b=a.node.getAttribute("linearGradient"==a.type||"radialGradient"==a.type?"gradientTransform":"pattern"==a.type?"patternTransform":"transform"),!b)return new d.Matrix;b=d._.svgTransform2string(b)}else b=d._.rgTransform.test(b)?o(b).replace(/\.{3}|\u2026/g,a._.transform||""):d._.svgTransform2string(b),n(b,"array")&&(b=d.path?d.path.toString.call(b):o(b)),a._.transform=b;var e=d._.transform2matrix(b,a.getBBox(1));return c?e:void(a.matrix=e)}function j(a){function b(a,b){var c=q(a.node,b);c=c&&c.match(f),c=c&&c[2],c&&"#"==c.charAt()&&(c=c.substring(1),c&&(h[c]=(h[c]||[]).concat(function(c){var d={};d[b]=URL(c),q(a.node,d)})))}function c(a){var b=q(a.node,"xlink:href");b&&"#"==b.charAt()&&(b=b.substring(1),b&&(h[b]=(h[b]||[]).concat(function(b){a.attr("xlink:href","#"+b)})))}for(var d,e=a.selectAll("*"),f=/^\s*url\(("|'|)(.*)\1\)\s*$/,g=[],h={},i=0,j=e.length;j>i;i++){d=e[i],b(d,"fill"),b(d,"stroke"),b(d,"filter"),b(d,"mask"),b(d,"clip-path"),c(d);var k=q(d.node,"id");k&&(q(d.node,{id:d.id}),g.push({old:k,id:d.id}))}for(i=0,j=g.length;j>i;i++){var l=h[g[i].old];if(l)for(var m=0,n=l.length;n>m;m++)l[m](g[i].id)}}function k(a,b,c){return function(d){var e=d.slice(a,b);return 1==e.length&&(e=e[0]),c?c(e):e}}function l(a){return function(){var b=a?"<"+this.type:"",c=this.node.attributes,d=this.node.childNodes;if(a)for(var e=0,f=c.length;f>e;e++)b+=" "+c[e].name+'="'+c[e].value.replace(/"/g,'\\"')+'"';if(d.length){for(a&&(b+=">"),e=0,f=d.length;f>e;e++)3==d[e].nodeType?b+=d[e].nodeValue:1==d[e].nodeType&&(b+=u(d[e]).toString());a&&(b+="</"+this.type+">")}else a&&(b+="/>");return b}}var m=e.prototype,n=d.is,o=String,p=d._unit2px,q=d._.$,r=d._.make,s=d._.getSomeDefs,t="hasOwnProperty",u=d._.wrap;m.getBBox=function(a){if(!d.Matrix||!d.path)return this.node.getBBox();var b=this,c=new d.Matrix;if(b.removed)return d._.box();for(;"use"==b.type;)if(a||(c=c.add(b.transform().localMatrix.translate(b.attr("x")||0,b.attr("y")||0))),b.original)b=b.original;else{var e=b.attr("xlink:href");b=b.original=b.node.ownerDocument.getElementById(e.substring(e.indexOf("#")+1))}var f=b._,g=d.path.get[b.type]||d.path.get.deflt;try{return a?(f.bboxwt=g?d.path.getBBox(b.realPath=g(b)):d._.box(b.node.getBBox()),d._.box(f.bboxwt)):(b.realPath=g(b),b.matrix=b.transform().localMatrix,f.bbox=d.path.getBBox(d.path.map(b.realPath,c.add(b.matrix))),d._.box(f.bbox))}catch(h){return d._.box()}};var v=function(){return this.string};m.transform=function(a){var b=this._;if(null==a){for(var c,e=this,f=new d.Matrix(this.node.getCTM()),g=i(this),h=[g],j=new d.Matrix,k=g.toTransformString(),l=o(g)==o(this.matrix)?o(b.transform):k;"svg"!=e.type&&(e=e.parent());)h.push(i(e));for(c=h.length;c--;)j.add(h[c]);return{string:l,globalMatrix:f,totalMatrix:j,localMatrix:g,diffMatrix:f.clone().add(g.invert()),global:f.toTransformString(),total:j.toTransformString(),local:k,toString:v}}return a instanceof d.Matrix?(this.matrix=a,this._.transform=a.toTransformString()):i(this,a),this.node&&("linearGradient"==this.type||"radialGradient"==this.type?q(this.node,{gradientTransform:this.matrix}):"pattern"==this.type?q(this.node,{patternTransform:this.matrix}):q(this.node,{transform:this.matrix})),this},m.parent=function(){return u(this.node.parentNode)},m.append=m.add=function(a){if(a){if("set"==a.type){var b=this;return a.forEach(function(a){b.add(a)}),this}a=u(a),this.node.appendChild(a.node),a.paper=this.paper}return this},m.appendTo=function(a){return a&&(a=u(a),a.append(this)),this},m.prepend=function(a){if(a){if("set"==a.type){var b,c=this;return a.forEach(function(a){b?b.after(a):c.prepend(a),b=a}),this}a=u(a);var d=a.parent();this.node.insertBefore(a.node,this.node.firstChild),this.add&&this.add(),a.paper=this.paper,this.parent()&&this.parent().add(),d&&d.add()}return this},m.prependTo=function(a){return a=u(a),a.prepend(this),this},m.before=function(a){if("set"==a.type){var b=this;return a.forEach(function(a){var c=a.parent();b.node.parentNode.insertBefore(a.node,b.node),c&&c.add()}),this.parent().add(),this}a=u(a);var c=a.parent();return this.node.parentNode.insertBefore(a.node,this.node),this.parent()&&this.parent().add(),c&&c.add(),a.paper=this.paper,this},m.after=function(a){a=u(a);var b=a.parent();return this.node.nextSibling?this.node.parentNode.insertBefore(a.node,this.node.nextSibling):this.node.parentNode.appendChild(a.node),this.parent()&&this.parent().add(),b&&b.add(),a.paper=this.paper,this},m.insertBefore=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.insertAfter=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node.nextSibling),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.remove=function(){var a=this.parent();return this.node.parentNode&&this.node.parentNode.removeChild(this.node),delete this.paper,this.removed=!0,a&&a.add(),this},m.select=function(a){return u(this.node.querySelector(a))},m.selectAll=function(a){for(var b=this.node.querySelectorAll(a),c=(d.set||Array)(),e=0;e<b.length;e++)c.push(u(b[e]));return c},m.asPX=function(a,b){return null==b&&(b=this.attr(a)),+p(this,a,b)},m.use=function(){var a,b=this.node.id;return b||(b=this.id,q(this.node,{id:b})),a="linearGradient"==this.type||"radialGradient"==this.type||"pattern"==this.type?r(this.type,this.node.parentNode):r("use",this.node.parentNode),q(a.node,{"xlink:href":"#"+b}),a.original=this,a},m.clone=function(){var a=u(this.node.cloneNode(!0));return q(a.node,"id")&&q(a.node,{id:a.id}),j(a),a.insertAfter(this),a},m.toDefs=function(){var a=s(this);return a.appendChild(this.node),this},m.pattern=m.toPattern=function(a,b,c,d){var e=r("pattern",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,a=a.x),q(e.node,{x:a,y:b,width:c,height:d,patternUnits:"userSpaceOnUse",id:e.id,viewBox:[a,b,c,d].join(" ")}),e.node.appendChild(this.node),e},m.marker=function(a,b,c,d,e,f){var g=r("marker",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,e=a.refX||a.cx,f=a.refY||a.cy,a=a.x),q(g.node,{viewBox:[a,b,c,d].join(" "),markerWidth:c,markerHeight:d,orient:"auto",refX:e||0,refY:f||0,id:g.id}),g.node.appendChild(this.node),g};var w=function(a,b,d,e){"function"!=typeof d||d.length||(e=d,d=c.linear),this.attr=a,this.dur=b,d&&(this.easing=d),e&&(this.callback=e)};d._.Animation=w,d.animation=function(a,b,c,d){return new w(a,b,c,d)},m.inAnim=function(){var a=this,b=[];for(var c in a.anims)a.anims[t](c)&&!function(a){b.push({anim:new w(a._attrs,a.dur,a.easing,a._callback),mina:a,curStatus:a.status(),status:function(b){return a.status(b)},stop:function(){a.stop()}})}(a.anims[c]);return b},d.animate=function(a,d,e,f,g,h){"function"!=typeof g||g.length||(h=g,g=c.linear);var i=c.time(),j=c(a,d,i,i+f,c.time,e,g);return h&&b.once("mina.finish."+j.id,h),j},m.stop=function(){for(var a=this.inAnim(),b=0,c=a.length;c>b;b++)a[b].stop();return this},m.animate=function(a,d,e,f){"function"!=typeof e||e.length||(f=e,e=c.linear),a instanceof w&&(f=a.callback,e=a.easing,d=a.dur,a=a.attr);var g,h,i,j,l=[],m=[],p={},q=this;for(var r in a)if(a[t](r)){q.equal?(j=q.equal(r,o(a[r])),g=j.from,h=j.to,i=j.f):(g=+q.attr(r),h=+a[r]);var s=n(g,"array")?g.length:1;p[r]=k(l.length,l.length+s,i),l=l.concat(g),m=m.concat(h)}var u=c.time(),v=c(l,m,u,u+d,c.time,function(a){var b={};for(var c in p)p[t](c)&&(b[c]=p[c](a));q.attr(b)},e);return q.anims[v.id]=v,v._attrs=a,v._callback=f,b("snap.animcreated."+q.id,v),b.once("mina.finish."+v.id,function(){delete q.anims[v.id],f&&f.call(q)}),b.once("mina.stop."+v.id,function(){delete q.anims[v.id]}),q};var x={};m.data=function(a,c){var e=x[this.id]=x[this.id]||{};if(0==arguments.length)return b("snap.data.get."+this.id,this,e,null),e; +if(1==arguments.length){if(d.is(a,"object")){for(var f in a)a[t](f)&&this.data(f,a[f]);return this}return b("snap.data.get."+this.id,this,e[a],a),e[a]}return e[a]=c,b("snap.data.set."+this.id,this,c,a),this},m.removeData=function(a){return null==a?x[this.id]={}:x[this.id]&&delete x[this.id][a],this},m.outerSVG=m.toString=l(1),m.innerSVG=l(),m.toDataURL=function(){if(a&&a.btoa){var b=this.getBBox(),c=d.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>',{x:+b.x.toFixed(3),y:+b.y.toFixed(3),width:+b.width.toFixed(3),height:+b.height.toFixed(3),contents:this.outerSVG()});return"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(c)))}},h.prototype.select=m.select,h.prototype.selectAll=m.selectAll}),d.plugin(function(a){function b(a,b,d,e,f,g){return null==b&&"[object SVGMatrix]"==c.call(a)?(this.a=a.a,this.b=a.b,this.c=a.c,this.d=a.d,this.e=a.e,void(this.f=a.f)):void(null!=a?(this.a=+a,this.b=+b,this.c=+d,this.d=+e,this.e=+f,this.f=+g):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0))}var c=Object.prototype.toString,d=String,e=Math,f="";!function(c){function g(a){return a[0]*a[0]+a[1]*a[1]}function h(a){var b=e.sqrt(g(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}c.add=function(a,c,d,e,f,g){var h,i,j,k,l=[[],[],[]],m=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],n=[[a,d,f],[c,e,g],[0,0,1]];for(a&&a instanceof b&&(n=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),h=0;3>h;h++)for(i=0;3>i;i++){for(k=0,j=0;3>j;j++)k+=m[h][j]*n[j][i];l[h][i]=k}return this.a=l[0][0],this.b=l[1][0],this.c=l[0][1],this.d=l[1][1],this.e=l[0][2],this.f=l[1][2],this},c.invert=function(){var a=this,c=a.a*a.d-a.b*a.c;return new b(a.d/c,-a.b/c,-a.c/c,a.a/c,(a.c*a.f-a.d*a.e)/c,(a.b*a.e-a.a*a.f)/c)},c.clone=function(){return new b(this.a,this.b,this.c,this.d,this.e,this.f)},c.translate=function(a,b){return this.add(1,0,0,1,a,b)},c.scale=function(a,b,c,d){return null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d),this},c.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var f=+e.cos(b).toFixed(9),g=+e.sin(b).toFixed(9);return this.add(f,g,-g,f,c,d),this.add(1,0,0,1,-c,-d)},c.x=function(a,b){return a*this.a+b*this.c+this.e},c.y=function(a,b){return a*this.b+b*this.d+this.f},c.get=function(a){return+this[d.fromCharCode(97+a)].toFixed(4)},c.toString=function(){return"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")"},c.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},c.determinant=function(){return this.a*this.d-this.b*this.c},c.split=function(){var b={};b.dx=this.e,b.dy=this.f;var c=[[this.a,this.c],[this.b,this.d]];b.scalex=e.sqrt(g(c[0])),h(c[0]),b.shear=c[0][0]*c[1][0]+c[0][1]*c[1][1],c[1]=[c[1][0]-c[0][0]*b.shear,c[1][1]-c[0][1]*b.shear],b.scaley=e.sqrt(g(c[1])),h(c[1]),b.shear/=b.scaley,this.determinant()<0&&(b.scalex=-b.scalex);var d=-c[0][1],f=c[1][1];return 0>f?(b.rotate=a.deg(e.acos(f)),0>d&&(b.rotate=360-b.rotate)):b.rotate=a.deg(e.asin(d)),b.isSimple=!(+b.shear.toFixed(9)||b.scalex.toFixed(9)!=b.scaley.toFixed(9)&&b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate,b},c.toTransformString=function(a){var b=a||this.split();return+b.shear.toFixed(9)?"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]:(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[+b.dx.toFixed(4),+b.dy.toFixed(4)]:f)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:f)+(b.rotate?"r"+[+b.rotate.toFixed(4),0,0]:f))}}(b.prototype),a.Matrix=b,a.matrix=function(a,c,d,e,f,g){return new b(a,c,d,e,f,g)}}),d.plugin(function(a,c,d,e,f){function g(d){return function(e){if(b.stop(),e instanceof f&&1==e.node.childNodes.length&&("radialGradient"==e.node.firstChild.tagName||"linearGradient"==e.node.firstChild.tagName||"pattern"==e.node.firstChild.tagName)&&(e=e.node.firstChild,n(this).appendChild(e),e=l(e)),e instanceof c)if("radialGradient"==e.type||"linearGradient"==e.type||"pattern"==e.type){e.node.id||p(e.node,{id:e.id});var g=q(e.node.id)}else g=e.attr(d);else if(g=a.color(e),g.error){var h=a(n(this).ownerSVGElement).gradient(e);h?(h.node.id||p(h.node,{id:h.id}),g=q(h.node.id)):g=e}else g=r(g);var i={};i[d]=g,p(this.node,i),this.node.style[d]=t}}function h(a){b.stop(),a==+a&&(a+="px"),this.node.style.fontSize=a}function i(a){for(var b=[],c=a.childNodes,d=0,e=c.length;e>d;d++){var f=c[d];3==f.nodeType&&b.push(f.nodeValue),"tspan"==f.tagName&&b.push(1==f.childNodes.length&&3==f.firstChild.nodeType?f.firstChild.nodeValue:i(f))}return b}function j(){return b.stop(),this.node.style.fontSize}var k=a._.make,l=a._.wrap,m=a.is,n=a._.getSomeDefs,o=/^url\(#?([^)]+)\)$/,p=a._.$,q=a.url,r=String,s=a._.separator,t="";b.on("snap.util.attr.mask",function(a){if(a instanceof c||a instanceof f){if(b.stop(),a instanceof f&&1==a.node.childNodes.length&&(a=a.node.firstChild,n(this).appendChild(a),a=l(a)),"mask"==a.type)var d=a;else d=k("mask",n(this)),d.node.appendChild(a.node);!d.node.id&&p(d.node,{id:d.id}),p(this.node,{mask:q(d.id)})}}),function(a){b.on("snap.util.attr.clip",a),b.on("snap.util.attr.clip-path",a),b.on("snap.util.attr.clipPath",a)}(function(a){if(a instanceof c||a instanceof f){if(b.stop(),"clipPath"==a.type)var d=a;else d=k("clipPath",n(this)),d.node.appendChild(a.node),!d.node.id&&p(d.node,{id:d.id});p(this.node,{"clip-path":q(d.node.id||d.id)})}}),b.on("snap.util.attr.fill",g("fill")),b.on("snap.util.attr.stroke",g("stroke"));var u=/^([lr])(?:\(([^)]*)\))?(.*)$/i;b.on("snap.util.grad.parse",function(a){a=r(a);var b=a.match(u);if(!b)return null;var c=b[1],d=b[2],e=b[3];return d=d.split(/\s*,\s*/).map(function(a){return+a==a?+a:a}),1==d.length&&0==d[0]&&(d=[]),e=e.split("-"),e=e.map(function(a){a=a.split(":");var b={color:a[0]};return a[1]&&(b.offset=parseFloat(a[1])),b}),{type:c,params:d,stops:e}}),b.on("snap.util.attr.d",function(c){b.stop(),m(c,"array")&&m(c[0],"array")&&(c=a.path.toString.call(c)),c=r(c),c.match(/[ruo]/i)&&(c=a.path.toAbsolute(c)),p(this.node,{d:c})})(-1),b.on("snap.util.attr.#text",function(a){b.stop(),a=r(a);for(var c=e.doc.createTextNode(a);this.node.firstChild;)this.node.removeChild(this.node.firstChild);this.node.appendChild(c)})(-1),b.on("snap.util.attr.path",function(a){b.stop(),this.attr({d:a})})(-1),b.on("snap.util.attr.class",function(a){b.stop(),this.node.className.baseVal=a})(-1),b.on("snap.util.attr.viewBox",function(a){var c;c=m(a,"object")&&"x"in a?[a.x,a.y,a.width,a.height].join(" "):m(a,"array")?a.join(" "):a,p(this.node,{viewBox:c}),b.stop()})(-1),b.on("snap.util.attr.transform",function(a){this.transform(a),b.stop()})(-1),b.on("snap.util.attr.r",function(a){"rect"==this.type&&(b.stop(),p(this.node,{rx:a,ry:a}))})(-1),b.on("snap.util.attr.textpath",function(a){if(b.stop(),"text"==this.type){var d,e,f;if(!a&&this.textPath){for(e=this.textPath;e.node.firstChild;)this.node.appendChild(e.node.firstChild);return e.remove(),void delete this.textPath}if(m(a,"string")){var g=n(this),h=l(g.parentNode).path(a);g.appendChild(h.node),d=h.id,h.attr({id:d})}else a=l(a),a instanceof c&&(d=a.attr("id"),d||(d=a.id,a.attr({id:d})));if(d)if(e=this.textPath,f=this.node,e)e.attr({"xlink:href":"#"+d});else{for(e=p("textPath",{"xlink:href":"#"+d});f.firstChild;)e.appendChild(f.firstChild);f.appendChild(e),this.textPath=l(e)}}})(-1),b.on("snap.util.attr.text",function(a){if("text"==this.type){for(var c=this.node,d=function(a){var b=p("tspan");if(m(a,"array"))for(var c=0;c<a.length;c++)b.appendChild(d(a[c]));else b.appendChild(e.doc.createTextNode(a));return b.normalize&&b.normalize(),b};c.firstChild;)c.removeChild(c.firstChild);for(var f=d(a);f.firstChild;)c.appendChild(f.firstChild)}b.stop()})(-1),b.on("snap.util.attr.fontSize",h)(-1),b.on("snap.util.attr.font-size",h)(-1),b.on("snap.util.getattr.transform",function(){return b.stop(),this.transform()})(-1),b.on("snap.util.getattr.textpath",function(){return b.stop(),this.textPath})(-1),function(){function c(c){return function(){b.stop();var d=e.doc.defaultView.getComputedStyle(this.node,null).getPropertyValue("marker-"+c);return"none"==d?d:a(e.doc.getElementById(d.match(o)[1]))}}function d(a){return function(c){b.stop();var d="marker"+a.charAt(0).toUpperCase()+a.substring(1);if(""==c||!c)return void(this.node.style[d]="none");if("marker"==c.type){var e=c.node.id;return e||p(c.node,{id:c.id}),void(this.node.style[d]=q(e))}}}b.on("snap.util.getattr.marker-end",c("end"))(-1),b.on("snap.util.getattr.markerEnd",c("end"))(-1),b.on("snap.util.getattr.marker-start",c("start"))(-1),b.on("snap.util.getattr.markerStart",c("start"))(-1),b.on("snap.util.getattr.marker-mid",c("mid"))(-1),b.on("snap.util.getattr.markerMid",c("mid"))(-1),b.on("snap.util.attr.marker-end",d("end"))(-1),b.on("snap.util.attr.markerEnd",d("end"))(-1),b.on("snap.util.attr.marker-start",d("start"))(-1),b.on("snap.util.attr.markerStart",d("start"))(-1),b.on("snap.util.attr.marker-mid",d("mid"))(-1),b.on("snap.util.attr.markerMid",d("mid"))(-1)}(),b.on("snap.util.getattr.r",function(){return"rect"==this.type&&p(this.node,"rx")==p(this.node,"ry")?(b.stop(),p(this.node,"rx")):void 0})(-1),b.on("snap.util.getattr.text",function(){if("text"==this.type||"tspan"==this.type){b.stop();var a=i(this.node);return 1==a.length?a[0]:a}})(-1),b.on("snap.util.getattr.#text",function(){return this.node.textContent})(-1),b.on("snap.util.getattr.viewBox",function(){b.stop();var c=p(this.node,"viewBox");return c?(c=c.split(s),a._.box(+c[0],+c[1],+c[2],+c[3])):void 0})(-1),b.on("snap.util.getattr.points",function(){var a=p(this.node,"points");return b.stop(),a?a.split(s):void 0})(-1),b.on("snap.util.getattr.path",function(){var a=p(this.node,"d");return b.stop(),a})(-1),b.on("snap.util.getattr.class",function(){return this.node.className.baseVal})(-1),b.on("snap.util.getattr.fontSize",j)(-1),b.on("snap.util.getattr.font-size",j)(-1)}),d.plugin(function(a,b){var c=/\S+/g,d=String,e=b.prototype;e.addClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(h.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e||k.push(f);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.removeClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(k.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e&&k.splice(e,1);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.hasClass=function(a){var b=this.node,d=b.className.baseVal,e=d.match(c)||[];return!!~e.indexOf(a)},e.toggleClass=function(a,b){if(null!=b)return b?this.addClass(a):this.removeClass(a);var d,e,f,g,h=(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];for(d=0;f=h[d++];)e=k.indexOf(f),~e?k.splice(e,1):k.push(f);return g=k.join(" "),j!=g&&(i.className.baseVal=g),this}}),d.plugin(function(){function a(a){return a}function c(a){return function(b){return+b.toFixed(3)+a}}var d={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"/":function(a,b){return a/b},"*":function(a,b){return a*b}},e=String,f=/[a-z]+$/i,g=/^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;b.on("snap.util.attr",function(a){var c=e(a).match(g);if(c){var h=b.nt(),i=h.substring(h.lastIndexOf(".")+1),j=this.attr(i),k={};b.stop();var l=c[3]||"",m=j.match(f),n=d[c[1]];if(m&&m==l?a=n(parseFloat(j),+c[2]):(j=this.asPX(i),a=n(this.asPX(i),this.asPX(i,c[2]+l))),isNaN(j)||isNaN(a))return;k[i]=a,this.attr(k)}})(-10),b.on("snap.util.equal",function(h,i){var j=e(this.attr(h)||""),k=e(i).match(g);if(k){b.stop();var l=k[3]||"",m=j.match(f),n=d[k[1]];return m&&m==l?{from:parseFloat(j),to:n(parseFloat(j),+k[2]),f:c(m)}:(j=this.asPX(h),{from:j,to:n(j,this.asPX(h,k[2]+l)),f:a})}})(-10)}),d.plugin(function(c,d,e,f){var g=e.prototype,h=c.is;g.rect=function(a,b,c,d,e,f){var g;return null==f&&(f=e),h(a,"object")&&"[object Object]"==a?g=a:null!=a&&(g={x:a,y:b,width:c,height:d},null!=e&&(g.rx=e,g.ry=f)),this.el("rect",g)},g.circle=function(a,b,c){var d;return h(a,"object")&&"[object Object]"==a?d=a:null!=a&&(d={cx:a,cy:b,r:c}),this.el("circle",d)};var i=function(){function a(){this.parentNode.removeChild(this)}return function(b,c){var d=f.doc.createElement("img"),e=f.doc.body;d.style.cssText="position:absolute;left:-9999em;top:-9999em",d.onload=function(){c.call(d),d.onload=d.onerror=null,e.removeChild(d)},d.onerror=a,e.appendChild(d),d.src=b}}();g.image=function(a,b,d,e,f){var g=this.el("image");if(h(a,"object")&&"src"in a)g.attr(a);else if(null!=a){var j={"xlink:href":a,preserveAspectRatio:"none"};null!=b&&null!=d&&(j.x=b,j.y=d),null!=e&&null!=f?(j.width=e,j.height=f):i(a,function(){c._.$(g.node,{width:this.offsetWidth,height:this.offsetHeight})}),c._.$(g.node,j)}return g},g.ellipse=function(a,b,c,d){var e;return h(a,"object")&&"[object Object]"==a?e=a:null!=a&&(e={cx:a,cy:b,rx:c,ry:d}),this.el("ellipse",e)},g.path=function(a){var b;return h(a,"object")&&!h(a,"array")?b=a:a&&(b={d:a}),this.el("path",b)},g.group=g.g=function(a){var b=this.el("g");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.svg=function(a,b,c,d,e,f,g,i){var j={};return h(a,"object")&&null==b?j=a:(null!=a&&(j.x=a),null!=b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),null!=e&&null!=f&&null!=g&&null!=i&&(j.viewBox=[e,f,g,i])),this.el("svg",j)},g.mask=function(a){var b=this.el("mask");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.ptrn=function(a,b,c,d,e,f,g,i){if(h(a,"object"))var j=a;else j={patternUnits:"userSpaceOnUse"},a&&(j.x=a),b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),j.viewBox=null!=e&&null!=f&&null!=g&&null!=i?[e,f,g,i]:[a||0,b||0,c||0,d||0];return this.el("pattern",j)},g.use=function(a){return null!=a?(a instanceof d&&(a.attr("id")||a.attr({id:c._.id(a)}),a=a.attr("id")),"#"==String(a).charAt()&&(a=a.substring(1)),this.el("use",{"xlink:href":"#"+a})):d.prototype.use.call(this)},g.symbol=function(a,b,c,d){var e={};return null!=a&&null!=b&&null!=c&&null!=d&&(e.viewBox=[a,b,c,d]),this.el("symbol",e)},g.text=function(a,b,c){var d={};return h(a,"object")?d=a:null!=a&&(d={x:a,y:b,text:c||""}),this.el("text",d)},g.line=function(a,b,c,d){var e={};return h(a,"object")?e=a:null!=a&&(e={x1:a,x2:c,y1:b,y2:d}),this.el("line",e)},g.polyline=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polyline",b)},g.polygon=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polygon",b)},function(){function d(){return this.selectAll("stop")}function e(a,b){var d=k("stop"),e={offset:+b+"%"};return a=c.color(a),e["stop-color"]=a.hex,a.opacity<1&&(e["stop-opacity"]=a.opacity),k(d,e),this.node.appendChild(d),this}function f(){if("linearGradient"==this.type){var a=k(this.node,"x1")||0,b=k(this.node,"x2")||1,d=k(this.node,"y1")||0,e=k(this.node,"y2")||0;return c._.box(a,d,math.abs(b-a),math.abs(e-d))}var f=this.node.cx||.5,g=this.node.cy||.5,h=this.node.r||0;return c._.box(f-h,g-h,2*h,2*h)}function h(a,c){function d(a,b){for(var c=(b-l)/(a-m),d=m;a>d;d++)g[d].offset=+(+l+c*(d-m)).toFixed(2);m=a,l=b}var e,f=b("snap.util.grad.parse",null,c).firstDefined();if(!f)return null;f.params.unshift(a),e="l"==f.type.toLowerCase()?i.apply(0,f.params):j.apply(0,f.params),f.type!=f.type.toLowerCase()&&k(e.node,{gradientUnits:"userSpaceOnUse"});var g=f.stops,h=g.length,l=0,m=0;h--;for(var n=0;h>n;n++)"offset"in g[n]&&d(n,g[n].offset);for(g[h].offset=g[h].offset||100,d(h,g[h].offset),n=0;h>=n;n++){var o=g[n];e.addStop(o.color,o.offset)}return e}function i(a,b,g,h,i){var j=c._.make("linearGradient",a);return j.stops=d,j.addStop=e,j.getBBox=f,null!=b&&k(j.node,{x1:b,y1:g,x2:h,y2:i}),j}function j(a,b,g,h,i,j){var l=c._.make("radialGradient",a);return l.stops=d,l.addStop=e,l.getBBox=f,null!=b&&k(l.node,{cx:b,cy:g,r:h}),null!=i&&null!=j&&k(l.node,{fx:i,fy:j}),l}var k=c._.$;g.gradient=function(a){return h(this.defs,a)},g.gradientLinear=function(a,b,c,d){return i(this.defs,a,b,c,d)},g.gradientRadial=function(a,b,c,d,e){return j(this.defs,a,b,c,d,e)},g.toString=function(){var a,b=this.node.ownerDocument,d=b.createDocumentFragment(),e=b.createElement("div"),f=this.node.cloneNode(!0);return d.appendChild(e),e.appendChild(f),c._.$(f,{xmlns:"http://www.w3.org/2000/svg"}),a=e.innerHTML,d.removeChild(d.firstChild),a},g.toDataURL=function(){return a&&a.btoa?"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(this))):void 0},g.clear=function(){for(var a,b=this.node.firstChild;b;)a=b.nextSibling,"defs"!=b.tagName?b.parentNode.removeChild(b):g.clear.call({node:b}),b=a}}()}),d.plugin(function(a,b){function c(a){var b=c.ps=c.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[K](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]}function d(a,b,c,d){return null==a&&(a=b=c=d=0),null==b&&(b=a.y,c=a.width,d=a.height,a=a.x),{x:a,y:b,width:c,w:c,height:d,h:d,x2:a+c,y2:b+d,cx:a+c/2,cy:b+d/2,r1:N.min(c,d)/2,r2:N.max(c,d)/2,r0:N.sqrt(c*c+d*d)/2,path:w(a,b,c,d),vb:[a,b,c,d].join(" ")}}function e(){return this.join(",").replace(L,"$1")}function f(a){var b=J(a);return b.toString=e,b}function g(a,b,c,d,e,f,g,h,j){return null==j?n(a,b,c,d,e,f,g,h):i(a,b,c,d,e,f,g,h,o(a,b,c,d,e,f,g,h,j))}function h(c,d){function e(a){return+(+a).toFixed(3)}return a._.cacher(function(a,f,h){a instanceof b&&(a=a.attr("d")),a=E(a);for(var j,k,l,m,n,o="",p={},q=0,r=0,s=a.length;s>r;r++){if(l=a[r],"M"==l[0])j=+l[1],k=+l[2];else{if(m=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6]),q+m>f){if(d&&!p.start){if(n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q),o+=["C"+e(n.start.x),e(n.start.y),e(n.m.x),e(n.m.y),e(n.x),e(n.y)],h)return o;p.start=o,o=["M"+e(n.x),e(n.y)+"C"+e(n.n.x),e(n.n.y),e(n.end.x),e(n.end.y),e(l[5]),e(l[6])].join(),q+=m,j=+l[5],k=+l[6];continue}if(!c&&!d)return n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q)}q+=m,j=+l[5],k=+l[6]}o+=l.shift()+l}return p.end=o,n=c?q:d?p:i(j,k,l[0],l[1],l[2],l[3],l[4],l[5],1)},null,a._.clone)}function i(a,b,c,d,e,f,g,h,i){var j=1-i,k=R(j,3),l=R(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*N.atan2(q-s,r-t)/O;return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}}function j(b,c,e,f,g,h,i,j){a.is(b,"array")||(b=[b,c,e,f,g,h,i,j]);var k=D.apply(null,b);return d(k.min.x,k.min.y,k.max.x-k.min.x,k.max.y-k.min.y)}function k(a,b,c){return b>=a.x&&b<=a.x+a.width&&c>=a.y&&c<=a.y+a.height}function l(a,b){return a=d(a),b=d(b),k(b,a.x,a.y)||k(b,a.x2,a.y)||k(b,a.x,a.y2)||k(b,a.x2,a.y2)||k(a,b.x,b.y)||k(a,b.x2,b.y)||k(a,b.x,b.y2)||k(a,b.x2,b.y2)||(a.x<b.x2&&a.x>b.x||b.x<a.x2&&b.x>a.x)&&(a.y<b.y2&&a.y>b.y||b.y<a.y2&&b.y>a.y)}function m(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function n(a,b,c,d,e,f,g,h,i){null==i&&(i=1),i=i>1?1:0>i?0:i;for(var j=i/2,k=12,l=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;k>p;p++){var q=j*l[p]+j,r=m(q,a,c,e,g),s=m(q,b,d,f,h),t=r*r+s*s;o+=n[p]*N.sqrt(t)}return j*o}function o(a,b,c,d,e,f,g,h,i){if(!(0>i||n(a,b,c,d,e,f,g,h)<i)){var j,k=1,l=k/2,m=k-l,o=.01;for(j=n(a,b,c,d,e,f,g,h,m);S(j-i)>o;)l/=2,m+=(i>j?1:-1)*l,j=n(a,b,c,d,e,f,g,h,m);return m}}function p(a,b,c,d,e,f,g,h){if(!(Q(a,c)<P(e,g)||P(a,c)>Q(e,g)||Q(b,d)<P(f,h)||P(b,d)>Q(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+Q(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+Q(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+Q(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+Q(f,h).toFixed(2)))return{x:l,y:m}}}}function q(a,b,c){var d=j(a),e=j(b);if(!l(d,e))return c?0:[];for(var f=n.apply(0,a),g=n.apply(0,b),h=~~(f/8),k=~~(g/8),m=[],o=[],q={},r=c?0:[],s=0;h+1>s;s++){var t=i.apply(0,a.concat(s/h));m.push({x:t.x,y:t.y,t:s/h})}for(s=0;k+1>s;s++)t=i.apply(0,b.concat(s/k)),o.push({x:t.x,y:t.y,t:s/k});for(s=0;h>s;s++)for(var u=0;k>u;u++){var v=m[s],w=m[s+1],x=o[u],y=o[u+1],z=S(w.x-v.x)<.001?"y":"x",A=S(y.x-x.x)<.001?"y":"x",B=p(v.x,v.y,w.x,w.y,x.x,x.y,y.x,y.y);if(B){if(q[B.x.toFixed(4)]==B.y.toFixed(4))continue;q[B.x.toFixed(4)]=B.y.toFixed(4);var C=v.t+S((B[z]-v[z])/(w[z]-v[z]))*(w.t-v.t),D=x.t+S((B[A]-x[A])/(y[A]-x[A]))*(y.t-x.t);C>=0&&1>=C&&D>=0&&1>=D&&(c?r++:r.push({x:B.x,y:B.y,t1:C,t2:D}))}}return r}function r(a,b){return t(a,b)}function s(a,b){return t(a,b,1)}function t(a,b,c){a=E(a),b=E(b);for(var d,e,f,g,h,i,j,k,l,m,n=c?0:[],o=0,p=a.length;p>o;o++){var r=a[o];if("M"==r[0])d=h=r[1],e=i=r[2];else{"C"==r[0]?(l=[d,e].concat(r.slice(1)),d=l[6],e=l[7]):(l=[d,e,d,e,h,i,h,i],d=h,e=i);for(var s=0,t=b.length;t>s;s++){var u=b[s];if("M"==u[0])f=j=u[1],g=k=u[2];else{"C"==u[0]?(m=[f,g].concat(u.slice(1)),f=m[6],g=m[7]):(m=[f,g,f,g,j,k,j,k],f=j,g=k);var v=q(l,m,c);if(c)n+=v;else{for(var w=0,x=v.length;x>w;w++)v[w].segment1=o,v[w].segment2=s,v[w].bez1=l,v[w].bez2=m;n=n.concat(v)}}}}}return n}function u(a,b,c){var d=v(a);return k(d,b,c)&&t(a,[["M",b,c],["H",d.x2+10]],1)%2==1}function v(a){var b=c(a);if(b.bbox)return J(b.bbox);if(!a)return d();a=E(a);for(var e,f=0,g=0,h=[],i=[],j=0,k=a.length;k>j;j++)if(e=a[j],"M"==e[0])f=e[1],g=e[2],h.push(f),i.push(g);else{var l=D(f,g,e[1],e[2],e[3],e[4],e[5],e[6]);h=h.concat(l.min.x,l.max.x),i=i.concat(l.min.y,l.max.y),f=e[5],g=e[6]}var m=P.apply(0,h),n=P.apply(0,i),o=Q.apply(0,h),p=Q.apply(0,i),q=d(m,n,o-m,p-n);return b.bbox=J(q),q}function w(a,b,c,d,f){if(f)return[["M",+a+ +f,b],["l",c-2*f,0],["a",f,f,0,0,1,f,f],["l",0,d-2*f],["a",f,f,0,0,1,-f,f],["l",2*f-c,0],["a",f,f,0,0,1,-f,-f],["l",0,2*f-d],["a",f,f,0,0,1,f,-f],["z"]];var g=[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]];return g.toString=e,g}function x(a,b,c,d,f){if(null==f&&null==d&&(d=c),a=+a,b=+b,c=+c,d=+d,null!=f)var g=Math.PI/180,h=a+c*Math.cos(-d*g),i=a+c*Math.cos(-f*g),j=b+c*Math.sin(-d*g),k=b+c*Math.sin(-f*g),l=[["M",h,j],["A",c,c,0,+(f-d>180),0,i,k]];else l=[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]];return l.toString=e,l}function y(b){var d=c(b),g=String.prototype.toLowerCase;if(d.rel)return f(d.rel);a.is(b,"array")&&a.is(b&&b[0],"array")||(b=a.parsePathString(b));var h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=b[0][1],j=b[0][2],k=i,l=j,m++,h.push(["M",i,j]));for(var n=m,o=b.length;o>n;n++){var p=h[n]=[],q=b[n];if(q[0]!=g.call(q[0]))switch(p[0]=g.call(q[0]),p[0]){case"a":p[1]=q[1],p[2]=q[2],p[3]=q[3],p[4]=q[4],p[5]=q[5],p[6]=+(q[6]-i).toFixed(3),p[7]=+(q[7]-j).toFixed(3);break;case"v":p[1]=+(q[1]-j).toFixed(3);break;case"m":k=q[1],l=q[2];default:for(var r=1,s=q.length;s>r;r++)p[r]=+(q[r]-(r%2?i:j)).toFixed(3)}else{p=h[n]=[],"m"==q[0]&&(k=q[1]+i,l=q[2]+j);for(var t=0,u=q.length;u>t;t++)h[n][t]=q[t]}var v=h[n].length;switch(h[n][0]){case"z":i=k,j=l;break;case"h":i+=+h[n][v-1];break;case"v":j+=+h[n][v-1];break;default:i+=+h[n][v-2],j+=+h[n][v-1]}}return h.toString=e,d.rel=f(h),h}function z(b){var d=c(b);if(d.abs)return f(d.abs);if(I(b,"array")&&I(b&&b[0],"array")||(b=a.parsePathString(b)),!b||!b.length)return[["M",0,0]];var g,h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=+b[0][1],j=+b[0][2],k=i,l=j,m++,h[0]=["M",i,j]);for(var n,o,p=3==b.length&&"M"==b[0][0]&&"R"==b[1][0].toUpperCase()&&"Z"==b[2][0].toUpperCase(),q=m,r=b.length;r>q;q++){if(h.push(n=[]),o=b[q],g=o[0],g!=g.toUpperCase())switch(n[0]=g.toUpperCase(),n[0]){case"A":n[1]=o[1],n[2]=o[2],n[3]=o[3],n[4]=o[4],n[5]=o[5],n[6]=+o[6]+i,n[7]=+o[7]+j;break;case"V":n[1]=+o[1]+j;break;case"H":n[1]=+o[1]+i;break;case"R":for(var s=[i,j].concat(o.slice(1)),t=2,u=s.length;u>t;t++)s[t]=+s[t]+i,s[++t]=+s[t]+j;h.pop(),h=h.concat(G(s,p));break;case"O":h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);break;case"U":h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));break;case"M":k=+o[1]+i,l=+o[2]+j;default:for(t=1,u=o.length;u>t;t++)n[t]=+o[t]+(t%2?i:j)}else if("R"==g)s=[i,j].concat(o.slice(1)),h.pop(),h=h.concat(G(s,p)),n=["R"].concat(o.slice(-2));else if("O"==g)h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);else if("U"==g)h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));else for(var v=0,w=o.length;w>v;v++)n[v]=o[v];if(g=g.toUpperCase(),"O"!=g)switch(n[0]){case"Z":i=+k,j=+l;break;case"H":i=n[1];break;case"V":j=n[1];break;case"M":k=n[n.length-2],l=n[n.length-1];default:i=n[n.length-2],j=n[n.length-1]}}return h.toString=e,d.abs=f(h),h}function A(a,b,c,d){return[a,b,c,d,c,d]}function B(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]}function C(b,c,d,e,f,g,h,i,j,k){var l,m=120*O/180,n=O/180*(+f||0),o=[],p=a._.cacher(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(b,c,-n),b=l.x,c=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(O/180*f),N.sin(O/180*f),(b-i)/2),r=(c-j)/2,s=q*q/(d*d)+r*r/(e*e);s>1&&(s=N.sqrt(s),d=s*d,e=s*e);var t=d*d,u=e*e,v=(g==h?-1:1)*N.sqrt(S((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*d*r/e+(b+i)/2,x=v*-e*q/d+(c+j)/2,y=N.asin(((c-x)/e).toFixed(9)),z=N.asin(((j-x)/e).toFixed(9));y=w>b?O-y:y,z=w>i?O-z:z,0>y&&(y=2*O+y),0>z&&(z=2*O+z),h&&y>z&&(y-=2*O),!h&&z>y&&(z-=2*O)}var A=z-y;if(S(A)>m){var B=z,D=i,E=j;z=y+m*(h&&z>y?1:-1),i=w+d*N.cos(z),j=x+e*N.sin(z),o=C(i,j,d,e,f,0,h,D,E,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),J=N.tan(A/4),K=4/3*d*J,L=4/3*e*J,M=[b,c],P=[b+K*G,c-L*F],Q=[i+K*I,j-L*H],R=[i,j];if(P[0]=2*M[0]-P[0],P[1]=2*M[1]-P[1],k)return[P,Q,R].concat(o);o=[P,Q,R].concat(o).join().split(",");for(var T=[],U=0,V=o.length;V>U;U++)T[U]=U%2?p(o[U-1],o[U],n).y:p(o[U],o[U+1],n).x;return T}function D(a,b,c,d,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=[],r=[[],[]],s=0;2>s;++s)if(0==s?(j=6*a-12*c+6*e,i=-3*a+9*c-9*e+3*g,k=3*c-3*a):(j=6*b-12*d+6*f,i=-3*b+9*d-9*f+3*h,k=3*d-3*b),S(i)<1e-12){if(S(j)<1e-12)continue;l=-k/j,l>0&&1>l&&q.push(l)}else o=j*j-4*k*i,p=N.sqrt(o),0>o||(m=(-j+p)/(2*i),m>0&&1>m&&q.push(m),n=(-j-p)/(2*i),n>0&&1>n&&q.push(n));for(var t,u=q.length,v=u;u--;)l=q[u],t=1-l,r[0][u]=t*t*t*a+3*t*t*l*c+3*t*l*l*e+l*l*l*g,r[1][u]=t*t*t*b+3*t*t*l*d+3*t*l*l*f+l*l*l*h;return r[0][v]=a,r[1][v]=b,r[0][v+1]=g,r[1][v+1]=h,r[0].length=r[1].length=v+2,{min:{x:P.apply(0,r[0]),y:P.apply(0,r[1])},max:{x:Q.apply(0,r[0]),y:Q.apply(0,r[1])}}}function E(a,b){var d=!b&&c(a);if(!b&&d.curve)return f(d.curve);for(var e=z(a),g=b&&z(b),h={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},i={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},j=(function(a,b,c){var d,e;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"].concat(C.apply(0,[b.x,b.y].concat(a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e].concat(a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"].concat(B(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"].concat(B(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"].concat(A(b.x,b.y,a[1],a[2]));break;case"H":a=["C"].concat(A(b.x,b.y,a[1],b.y));break;case"V":a=["C"].concat(A(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"].concat(A(b.x,b.y,b.X,b.Y))}return a}),k=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)m[b]="A",g&&(n[b]="A"),a.splice(b++,0,["C"].concat(c.splice(0,6)));a.splice(b,1),r=Q(e.length,g&&g.length||0)}},l=function(a,b,c,d,f){a&&b&&"M"==a[f][0]&&"M"!=b[f][0]&&(b.splice(f,0,["M",d.x,d.y]),c.bx=0,c.by=0,c.x=a[f][1],c.y=a[f][2],r=Q(e.length,g&&g.length||0))},m=[],n=[],o="",p="",q=0,r=Q(e.length,g&&g.length||0);r>q;q++){e[q]&&(o=e[q][0]),"C"!=o&&(m[q]=o,q&&(p=m[q-1])),e[q]=j(e[q],h,p),"A"!=m[q]&&"C"==o&&(m[q]="C"),k(e,q),g&&(g[q]&&(o=g[q][0]),"C"!=o&&(n[q]=o,q&&(p=n[q-1])),g[q]=j(g[q],i,p),"A"!=n[q]&&"C"==o&&(n[q]="C"),k(g,q)),l(e,g,h,i,q),l(g,e,i,h,q);var s=e[q],t=g&&g[q],u=s.length,v=g&&t.length;h.x=s[u-2],h.y=s[u-1],h.bx=M(s[u-4])||h.x,h.by=M(s[u-3])||h.y,i.bx=g&&(M(t[v-4])||i.x),i.by=g&&(M(t[v-3])||i.y),i.x=g&&t[v-2],i.y=g&&t[v-1]}return g||(d.curve=f(e)),g?[e,g]:e}function F(a,b){if(!b)return a;var c,d,e,f,g,h,i;for(a=E(a),e=0,g=a.length;g>e;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a}function G(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}var H=b.prototype,I=a.is,J=a._.clone,K="hasOwnProperty",L=/,?([a-z]),?/gi,M=parseFloat,N=Math,O=N.PI,P=N.min,Q=N.max,R=N.pow,S=N.abs,T=h(1),U=h(),V=h(0,1),W=a._unit2px,X={path:function(a){return a.attr("path")},circle:function(a){var b=W(a);return x(b.cx,b.cy,b.r)},ellipse:function(a){var b=W(a);return x(b.cx||0,b.cy||0,b.rx,b.ry)},rect:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height,b.rx,b.ry)},image:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height)},line:function(a){return"M"+[a.attr("x1")||0,a.attr("y1")||0,a.attr("x2"),a.attr("y2")]},polyline:function(a){return"M"+a.attr("points")},polygon:function(a){return"M"+a.attr("points")+"z"},deflt:function(a){var b=a.node.getBBox();return w(b.x,b.y,b.width,b.height)}};a.path=c,a.path.getTotalLength=T,a.path.getPointAtLength=U,a.path.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return V(a,b).end;var d=V(a,c,1);return b?V(d,b).end:d},H.getTotalLength=function(){return this.node.getTotalLength?this.node.getTotalLength():void 0},H.getPointAtLength=function(a){return U(this.attr("d"),a)},H.getSubpath=function(b,c){return a.path.getSubpath(this.attr("d"),b,c)},a._.box=d,a.path.findDotsAtSegment=i,a.path.bezierBBox=j,a.path.isPointInsideBBox=k,a.closest=function(b,c,e,f){for(var g=100,h=d(b-g/2,c-g/2,g,g),i=[],j=e[0].hasOwnProperty("x")?function(a){return{x:e[a].x,y:e[a].y}}:function(a){return{x:e[a],y:f[a]}},l=0;1e6>=g&&!l;){for(var m=0,n=e.length;n>m;m++){var o=j(m);if(k(h,o.x,o.y)){l++,i.push(o);break}}l||(g*=2,h=d(b-g/2,c-g/2,g,g))}if(1e6!=g){var p,q=1/0;for(m=0,n=i.length;n>m;m++){var r=a.len(b,c,i[m].x,i[m].y);q>r&&(q=r,i[m].len=r,p=i[m])}return p}},a.path.isBBoxIntersect=l,a.path.intersection=r,a.path.intersectionNumber=s,a.path.isPointInside=u,a.path.getBBox=v,a.path.get=X,a.path.toRelative=y,a.path.toAbsolute=z,a.path.toCubic=E,a.path.map=F,a.path.toString=e,a.path.clone=f}),d.plugin(function(a){var d=Math.max,e=Math.min,f=function(a){if(this.items=[],this.bindings={},this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)a[b]&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},g=f.prototype;g.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],a&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},g.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},g.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this},g.animate=function(d,e,f,g){"function"!=typeof f||f.length||(g=f,f=c.linear),d instanceof a._.Animation&&(g=d.callback,f=d.easing,e=f.dur,d=d.attr);var h=arguments;if(a.is(d,"array")&&a.is(h[h.length-1],"array"))var i=!0;var j,k=function(){j?this.b=j:j=this.b},l=0,m=this,n=g&&function(){++l==m.length&&g.call(this) +};return this.forEach(function(a,c){b.once("snap.animcreated."+a.id,k),i?h[c]&&a.animate.apply(a,h[c]):a.animate(d,e,f,n)})},g.remove=function(){for(;this.length;)this.pop().remove();return this},g.bind=function(a,b,c){var d={};if("function"==typeof b)this.bindings[a]=b;else{var e=c||a;this.bindings[a]=function(a){d[e]=a,b.attr(d)}}return this},g.attr=function(a){var b={};for(var c in a)this.bindings[c]?this.bindings[c](a[c]):b[c]=a[c];for(var d=0,e=this.items.length;e>d;d++)this.items[d].attr(b);return this},g.clear=function(){for(;this.length;)this.pop()},g.splice=function(a,b){a=0>a?d(this.length+a,0):a,b=d(0,e(this.length-a,b));var c,g=[],h=[],i=[];for(c=2;c<arguments.length;c++)i.push(arguments[c]);for(c=0;b>c;c++)h.push(this[a+c]);for(;c<this.length-a;c++)g.push(this[a+c]);var j=i.length;for(c=0;c<j+g.length;c++)this.items[a+c]=this[a+c]=j>c?i[c]:g[c-j];for(c=this.items.length=this.length-=b-j;this[c];)delete this[c++];return new f(h)},g.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0;return!1},g.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},g.getBBox=function(){for(var a=[],b=[],c=[],f=[],g=this.items.length;g--;)if(!this.items[g].removed){var h=this.items[g].getBBox();a.push(h.x),b.push(h.y),c.push(h.x+h.width),f.push(h.y+h.height)}return a=e.apply(0,a),b=e.apply(0,b),c=d.apply(0,c),f=d.apply(0,f),{x:a,y:b,x2:c,y2:f,width:c-a,height:f-b,cx:a+(c-a)/2,cy:b+(f-b)/2}},g.clone=function(a){a=new f;for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},g.toString=function(){return"Snap‘s set"},g.type="set",a.Set=f,a.set=function(){var a=new f;return arguments.length&&a.push.apply(a,Array.prototype.slice.call(arguments,0)),a}}),d.plugin(function(a,c){function d(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}}function e(b,c,e){c=p(c).replace(/\.{3}|\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];for(var f,g,h,i,l=Math.max(b.length,c.length),m=[],n=[],o=0;l>o;o++){if(h=b[o]||d(c[o]),i=c[o]||d(h),h[0]!=i[0]||"r"==h[0].toLowerCase()&&(h[2]!=i[2]||h[3]!=i[3])||"s"==h[0].toLowerCase()&&(h[3]!=i[3]||h[4]!=i[4])){b=a._.transform2matrix(b,e()),c=a._.transform2matrix(c,e()),m=[["m",b.a,b.b,b.c,b.d,b.e,b.f]],n=[["m",c.a,c.b,c.c,c.d,c.e,c.f]];break}for(m[o]=[],n[o]=[],f=0,g=Math.max(h.length,i.length);g>f;f++)f in h&&(m[o][f]=h[f]),f in i&&(n[o][f]=i[f])}return{from:k(m),to:k(n),f:j(m)}}function f(a){return a}function g(a){return function(b){return+b.toFixed(3)+a}}function h(a){return a.join(" ")}function i(b){return a.rgb(b[0],b[1],b[2])}function j(a){var b,c,d,e,f,g,h=0,i=[];for(b=0,c=a.length;c>b;b++){for(f="[",g=['"'+a[b][0]+'"'],d=1,e=a[b].length;e>d;d++)g[d]="val["+h++ +"]";f+=g+"]",i[b]=f}return Function("val","return Snap.path.toString.call(["+i+"])")}function k(a){for(var b=[],c=0,d=a.length;d>c;c++)for(var e=1,f=a[c].length;f>e;e++)b.push(a[c][e]);return b}function l(a){return isFinite(parseFloat(a))}function m(b,c){return a.is(b,"array")&&a.is(c,"array")?b.toString()==c.toString():!1}var n={},o=/[a-z]+$/i,p=String;n.stroke=n.fill="colour",c.prototype.equal=function(a,c){return b("snap.util.equal",this,a,c).firstDefined()},b.on("snap.util.equal",function(b,c){var d,q,r=p(this.attr(b)||""),s=this;if(l(r)&&l(c))return{from:parseFloat(r),to:parseFloat(c),f:f};if("colour"==n[b])return d=a.color(r),q=a.color(c),{from:[d.r,d.g,d.b,d.opacity],to:[q.r,q.g,q.b,q.opacity],f:i};if("viewBox"==b)return d=this.attr(b).vb.split(" ").map(Number),q=c.split(" ").map(Number),{from:d,to:q,f:h};if("transform"==b||"gradientTransform"==b||"patternTransform"==b)return c instanceof a.Matrix&&(c=c.toTransformString()),a._.rgTransform.test(c)||(c=a._.svgTransform2string(c)),e(r,c,function(){return s.getBBox(1)});if("d"==b||"path"==b)return d=a.path.toCubic(r,c),{from:k(d[0]),to:k(d[1]),f:j(d[0])};if("points"==b)return d=p(r).split(a._.separator),q=p(c).split(a._.separator),{from:d,to:q,f:function(a){return a}};var t=r.match(o),u=p(c).match(o);return t&&m(t,u)?{from:parseFloat(r),to:parseFloat(c),f:g(t)}:{from:this.asPX(b),to:this.asPX(b,c),f:f}})}),d.plugin(function(a,c,d,e){for(var f=c.prototype,g="hasOwnProperty",h=("createTouch"in e.doc),i=["click","dblclick","mousedown","mousemove","mouseout","mouseover","mouseup","touchstart","touchmove","touchend","touchcancel"],j={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},k=(function(a,b){var c="y"==a?"scrollTop":"scrollLeft",d=b&&b.node?b.node.ownerDocument:e.doc;return d[c in d.documentElement?"documentElement":"body"][c]}),l=function(){return this.originalEvent.preventDefault()},m=function(){return this.originalEvent.stopPropagation()},n=function(a,b,c,d){var e=h&&j[b]?j[b]:b,f=function(e){var f=k("y",d),i=k("x",d);if(h&&j[g](b))for(var n=0,o=e.targetTouches&&e.targetTouches.length;o>n;n++)if(e.targetTouches[n].target==a||a.contains(e.targetTouches[n].target)){var p=e;e=e.targetTouches[n],e.originalEvent=p,e.preventDefault=l,e.stopPropagation=m;break}var q=e.clientX+i,r=e.clientY+f;return c.call(d,e,q,r)};return b!==e&&a.addEventListener(b,f,!1),a.addEventListener(e,f,!1),function(){return b!==e&&a.removeEventListener(b,f,!1),a.removeEventListener(e,f,!1),!0}},o=[],p=function(a){for(var c,d=a.clientX,e=a.clientY,f=k("y"),g=k("x"),i=o.length;i--;){if(c=o[i],h){for(var j,l=a.touches&&a.touches.length;l--;)if(j=a.touches[l],j.identifier==c.el._drag.id||c.el.node.contains(j.target)){d=j.clientX,e=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();{var m=c.el.node;m.nextSibling,m.parentNode,m.style.display}d+=g,e+=f,b("snap.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},q=function(c){a.unmousemove(p).unmouseup(q);for(var d,e=o.length;e--;)d=o[e],d.el._drag={},b("snap.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,c),b.off("snap.drag.*."+d.el.id);o=[]},r=i.length;r--;)!function(b){a[b]=f[b]=function(c,d){if(a.is(c,"function"))this.events=this.events||[],this.events.push({name:b,f:c,unbind:n(this.node||document,b,c,d||this)});else for(var e=0,f=this.events.length;f>e;e++)if(this.events[e].name==b)try{this.events[e].f.call(this)}catch(g){}return this},a["un"+b]=f["un"+b]=function(a){for(var c=this.events||[],d=c.length;d--;)if(c[d].name==b&&(c[d].f==a||!a))return c[d].unbind(),c.splice(d,1),!c.length&&delete this.events,this;return this}}(i[r]);f.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},f.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var s=[];f.drag=function(c,d,e,f,g,h){function i(i,j,l){(i.originalEvent||i).preventDefault(),k._drag.x=j,k._drag.y=l,k._drag.id=i.identifier,!o.length&&a.mousemove(p).mouseup(q),o.push({el:k,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("snap.drag.start."+k.id,d),c&&b.on("snap.drag.move."+k.id,c),e&&b.on("snap.drag.end."+k.id,e),b("snap.drag.start."+k.id,g||f||k,j,l,i)}function j(a,c,d){b("snap.draginit."+k.id,k,a,c,d)}var k=this;if(!arguments.length){var l;return k.drag(function(a,b){this.attr({transform:l+(l?"T":"t")+[a,b]})},function(){l=this.transform().local})}return b.on("snap.draginit."+k.id,i),k._drag={},s.push({el:k,start:i,init:j}),k.mousedown(j),k},f.undrag=function(){for(var c=s.length;c--;)s[c].el==this&&(this.unmousedown(s[c].init),s.splice(c,1),b.unbind("snap.drag.*."+this.id),b.unbind("snap.draginit."+this.id));return!s.length&&a.unmousemove(p).unmouseup(q),this}}),d.plugin(function(a,c,d){var e=(c.prototype,d.prototype),f=/^\s*url\((.+)\)/,g=String,h=a._.$;a.filter={},e.filter=function(b){var d=this;"svg"!=d.type&&(d=d.paper);var e=a.parse(g(b)),f=a._.id(),i=(d.node.offsetWidth,d.node.offsetHeight,h("filter"));return h(i,{id:f,filterUnits:"userSpaceOnUse"}),i.appendChild(e.node),d.defs.appendChild(i),new c(i)},b.on("snap.util.getattr.filter",function(){b.stop();var c=h(this.node,"filter");if(c){var d=g(c).match(f);return d&&a.select(d[1])}}),b.on("snap.util.attr.filter",function(d){if(d instanceof c&&"filter"==d.type){b.stop();var e=d.node.id;e||(h(d.node,{id:d.id}),e=d.id),h(this.node,{filter:a.url(e)})}d&&"none"!=d||(b.stop(),this.node.removeAttribute("filter"))}),a.filter.blur=function(b,c){null==b&&(b=2);var d=null==c?b:[b,c];return a.format('<feGaussianBlur stdDeviation="{def}"/>',{def:d})},a.filter.blur.toString=function(){return this()},a.filter.shadow=function(b,c,d,e,f){return"string"==typeof d&&(e=d,f=e,d=4),"string"!=typeof e&&(f=e,e="#000"),e=e||"#000",null==d&&(d=4),null==f&&(f=1),null==b&&(b=0,c=2),null==c&&(c=b),e=a.color(e),a.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>',{color:e,dx:b,dy:c,blur:d,opacity:f})},a.filter.shadow.toString=function(){return this()},a.filter.grayscale=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>',{a:.2126+.7874*(1-b),b:.7152-.7152*(1-b),c:.0722-.0722*(1-b),d:.2126-.2126*(1-b),e:.7152+.2848*(1-b),f:.0722-.0722*(1-b),g:.2126-.2126*(1-b),h:.0722+.9278*(1-b)})},a.filter.grayscale.toString=function(){return this()},a.filter.sepia=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>',{a:.393+.607*(1-b),b:.769-.769*(1-b),c:.189-.189*(1-b),d:.349-.349*(1-b),e:.686+.314*(1-b),f:.168-.168*(1-b),g:.272-.272*(1-b),h:.534-.534*(1-b),i:.131+.869*(1-b)})},a.filter.sepia.toString=function(){return this()},a.filter.saturate=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="saturate" values="{amount}"/>',{amount:1-b})},a.filter.saturate.toString=function(){return this()},a.filter.hueRotate=function(b){return b=b||0,a.format('<feColorMatrix type="hueRotate" values="{angle}"/>',{angle:b})},a.filter.hueRotate.toString=function(){return this()},a.filter.invert=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>',{amount:b,amount2:1-b})},a.filter.invert.toString=function(){return this()},a.filter.brightness=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>',{amount:b})},a.filter.brightness.toString=function(){return this()},a.filter.contrast=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>',{amount:b,amount2:.5-b/2})},a.filter.contrast.toString=function(){return this()}}),d.plugin(function(a,b){var c=a._.box,d=a.is,e=/^[^a-z]*([tbmlrc])/i,f=function(){return"T"+this.dx+","+this.dy};b.prototype.getAlign=function(a,b){null==b&&d(a,"string")&&(b=a,a=null),a=a||this.paper;var g=a.getBBox?a.getBBox():c(a),h=this.getBBox(),i={};switch(b=b&&b.match(e),b=b?b[1].toLowerCase():"c"){case"t":i.dx=0,i.dy=g.y-h.y;break;case"b":i.dx=0,i.dy=g.y2-h.y2;break;case"m":i.dx=0,i.dy=g.cy-h.cy;break;case"l":i.dx=g.x-h.x,i.dy=0;break;case"r":i.dx=g.x2-h.x2,i.dy=0;break;default:i.dx=g.cx-h.cx,i.dy=0}return i.toString=f,i},b.prototype.align=function(a,b){return this.transform("..."+this.getAlign(a,b))}}),d}); diff --git a/web/pgadmin/misc/static/explain/js/snap.svg.js b/web/pgadmin/misc/static/explain/js/snap.svg.js new file mode 100644 index 0000000..ef0fb6d --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg.js @@ -0,0 +1,8149 @@ +// Snap.svg 0.4.1 +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// build: 2015-04-13 +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ┌────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.4.2 - JavaScript Events Library │ \\ +// ├────────────────────────────────────────────────────────────┤ \\ +// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// └────────────────────────────────────────────────────────────┘ \\ +(function (glob) { + var version = "0.4.2", + has = "hasOwnProperty", + separator = /[\.\/]/, + comaseparator = /\s*,\s*/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + firstDefined = function () { + for (var i = 0, ii = this.length; i < ii; i++) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + lastDefined = function () { + var i = this.length; + while (--i) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + /*\ + * eve + [ method ] + * Fires event with given `name`, given scope and other parameters. + > Arguments + - name (string) name of the *event*, dot (`.`) or slash (`/`) separated + - scope (object) context for the event handlers + - varargs (...) the rest of arguments will be sent to event handlers + = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value. + \*/ + eve = function (name, scope) { + name = String(name); + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + ce = current_event, + errors = []; + out.firstDefined = firstDefined; + out.lastDefined = lastDefined; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + break; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + } + } + stop = oldstop; + current_event = ce; + return out; + }; + // Undocumented. Debug only. + eve._events = events; + /*\ + * eve.listeners + [ method ] + * Internal method which gives you array of all event handlers that will be triggered by the given `name`. + > Arguments + - name (string) name of the event, dot (`.`) or slash (`/`) separated + = (array) array of event handlers + \*/ + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + /*\ + * eve.on + [ method ] + ** + * Binds given event handler with a given name. You can use wildcards “`*`” for the names: + | eve.on("*.under.*", f); + | eve("mouse.under.floor"); // triggers f + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. + > Example: + | eve.on("mouse", eatIt)(2); + | eve.on("mouse", scream); + | eve.on("mouse", catchIt)(1); + * This will ensure that `catchIt` function will be called before `eatIt`. + * + * If you want to put your handler before non-indexed handlers, specify a negative value. + * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. + \*/ + eve.on = function (name, f) { + name = String(name); + if (typeof f != "function") { + return function () {}; + } + var names = name.split(comaseparator); + for (var i = 0, ii = names.length; i < ii; i++) { + (function (name) { + var names = name.split(separator), + e = events, + exist; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + exist = true; + break; + } + !exist && e.f.push(f); + }(names[i])); + } + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + /*\ + * eve.f + [ method ] + ** + * Returns function that will fire given event with optional arguments. + * Arguments that will be passed to the result function will be also + * concated to the list of final arguments. + | el.onclick = eve.f("click", 1, 2); + | eve.on("click", function (a, b, c) { + | console.log(a, b, c); // 1, 2, [event object] + | }); + > Arguments + - event (string) event name + - varargs (…) and any other arguments + = (function) possible event handler function + \*/ + eve.f = function (event) { + var attrs = [].slice.call(arguments, 1); + return function () { + eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); + }; + }; + /*\ + * eve.stop + [ method ] + ** + * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. + \*/ + eve.stop = function () { + stop = 1; + }; + /*\ + * eve.nt + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + > Arguments + ** + - subname (string) #optional subname of the event + ** + = (string) name of the event, if `subname` is not specified + * or + = (boolean) `true`, if current event’s name contains `subname` + \*/ + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + /*\ + * eve.nts + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + ** + = (array) names of the event + \*/ + eve.nts = function () { + return current_event.split(separator); + }; + /*\ + * eve.off + [ method ] + ** + * Removes given function from the list of event listeners assigned to given name. + * If no arguments specified all the events will be cleared. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + \*/ + /*\ + * eve.unbind + [ method ] + ** + * See @eve.off + \*/ + eve.off = eve.unbind = function (name, f) { + if (!name) { + eve._events = events = {n: {}}; + return; + } + var names = name.split(comaseparator); + if (names.length > 1) { + for (var i = 0, ii = names.length; i < ii; i++) { + eve.off(names[i], f); + } + return; + } + names = name.split(separator); + var e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + /*\ + * eve.once + [ method ] + ** + * Binds given event handler with a given name to only run once then unbind itself. + | eve.once("login", f); + | eve("login"); // triggers f + | eve("login"); // no listeners + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) same return function as @eve.on + \*/ + eve.once = function (name, f) { + var f2 = function () { + eve.unbind(name, f2); + return f.apply(this, arguments); + }; + return eve.on(name, f2); + }; + /*\ + * eve.version + [ property (string) ] + ** + * Current version of the library. + \*/ + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define === "function" && define.amd ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); +})(this); + +(function (glob, factory) { + // AMD support + if (typeof define == "function" && define.amd) { + // Define as an anonymous module + define(["eve"], function (eve) { + return factory(glob, eve); + }); + } else if (typeof exports != 'undefined') { + // Next for Node.js or CommonJS + var eve = require('eve'); + module.exports = factory(glob, eve); + } else { + // Browser globals (glob is window) + // Snap adds itself to window + factory(glob, glob.eve); + } +}(window || this, function (window, eve) { +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +var mina = (function (eve) { + var animations = {}, + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + isArray = Array.isArray || function (a) { + return a instanceof Array || + Object.prototype.toString.call(a) == "[object Array]"; + }, + idgen = 0, + idprefix = "M" + (+new Date).toString(36), + ID = function () { + return idprefix + (idgen++).toString(36); + }, + diff = function (a, b, A, B) { + if (isArray(a)) { + res = []; + for (var i = 0, ii = a.length; i < ii; i++) { + res[i] = diff(a[i], b, A[i], B); + } + return res; + } + var dif = (A - a) / (B - b); + return function (bb) { + return a + dif * (bb - b); + }; + }, + timer = Date.now || function () { + return +new Date; + }, + sta = function (val) { + var a = this; + if (val == null) { + return a.s; + } + var ds = a.s - val; + a.b += a.dur * ds; + a.B += a.dur * ds; + a.s = val; + }, + speed = function (val) { + var a = this; + if (val == null) { + return a.spd; + } + a.spd = val; + }, + duration = function (val) { + var a = this; + if (val == null) { + return a.dur; + } + a.s = a.s * val / a.dur; + a.dur = val; + }, + stopit = function () { + var a = this; + delete animations[a.id]; + a.update(); + eve("mina.stop." + a.id, a); + }, + pause = function () { + var a = this; + if (a.pdif) { + return; + } + delete animations[a.id]; + a.update(); + a.pdif = a.get() - a.b; + }, + resume = function () { + var a = this; + if (!a.pdif) { + return; + } + a.b = a.get() - a.pdif; + delete a.pdif; + animations[a.id] = a; + }, + update = function () { + var a = this, + res; + if (isArray(a.start)) { + res = []; + for (var j = 0, jj = a.start.length; j < jj; j++) { + res[j] = +a.start[j] + + (a.end[j] - a.start[j]) * a.easing(a.s); + } + } else { + res = +a.start + (a.end - a.start) * a.easing(a.s); + } + a.set(res); + }, + frame = function () { + var len = 0; + for (var i in animations) if (animations.hasOwnProperty(i)) { + var a = animations[i], + b = a.get(), + res; + len++; + a.s = (b - a.b) / (a.dur / a.spd); + if (a.s >= 1) { + delete animations[i]; + a.s = 1; + len--; + (function (a) { + setTimeout(function () { + eve("mina.finish." + a.id, a); + }); + }(a)); + } + a.update(); + } + len && requestAnimFrame(frame); + }, + /*\ + * mina + [ method ] + ** + * Generic animation of numbers + ** + - a (number) start _slave_ number + - A (number) end _slave_ number + - b (number) start _master_ number (start time in general case) + - B (number) end _master_ number (end time in gereal case) + - get (function) getter of _master_ number (see @mina.time) + - set (function) setter of _slave_ number + - easing (function) #optional easing function, default is @mina.linear + = (object) animation descriptor + o { + o id (string) animation id, + o start (number) start _slave_ number, + o end (number) end _slave_ number, + o b (number) start _master_ number, + o s (number) animation status (0..1), + o dur (number) animation duration, + o spd (number) animation speed, + o get (function) getter of _master_ number (see @mina.time), + o set (function) setter of _slave_ number, + o easing (function) easing function, default is @mina.linear, + o status (function) status getter/setter, + o speed (function) speed getter/setter, + o duration (function) duration getter/setter, + o stop (function) animation stopper + o pause (function) pauses the animation + o resume (function) resumes the animation + o update (function) calles setter with the right value of the animation + o } + \*/ + mina = function (a, A, b, B, get, set, easing) { + var anim = { + id: ID(), + start: a, + end: A, + b: b, + s: 0, + dur: B - b, + spd: 1, + get: get, + set: set, + easing: easing || mina.linear, + status: sta, + speed: speed, + duration: duration, + stop: stopit, + pause: pause, + resume: resume, + update: update + }; + animations[anim.id] = anim; + var len = 0, i; + for (i in animations) if (animations.hasOwnProperty(i)) { + len++; + if (len == 2) { + break; + } + } + len == 1 && requestAnimFrame(frame); + return anim; + }; + /*\ + * mina.time + [ method ] + ** + * Returns the current time. Equivalent to: + | function () { + | return (new Date).getTime(); + | } + \*/ + mina.time = timer; + /*\ + * mina.getById + [ method ] + ** + * Returns an animation by its id + - id (string) animation's id + = (object) See @mina + \*/ + mina.getById = function (id) { + return animations[id] || null; + }; + + /*\ + * mina.linear + [ method ] + ** + * Default linear easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.linear = function (n) { + return n; + }; + /*\ + * mina.easeout + [ method ] + ** + * Easeout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeout = function (n) { + return Math.pow(n, 1.7); + }; + /*\ + * mina.easein + [ method ] + ** + * Easein easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easein = function (n) { + return Math.pow(n, .48); + }; + /*\ + * mina.easeinout + [ method ] + ** + * Easeinout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeinout = function (n) { + if (n == 1) { + return 1; + } + if (n == 0) { + return 0; + } + var q = .48 - n / 1.04, + Q = Math.sqrt(.1734 + q * q), + x = Q - q, + X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }; + /*\ + * mina.backin + [ method ] + ** + * Backin easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backin = function (n) { + if (n == 1) { + return 1; + } + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }; + /*\ + * mina.backout + [ method ] + ** + * Backout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backout = function (n) { + if (n == 0) { + return 0; + } + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }; + /*\ + * mina.elastic + [ method ] + ** + * Elastic easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.elastic = function (n) { + if (n == !!n) { + return n; + } + return Math.pow(2, -10 * n) * Math.sin((n - .075) * + (2 * Math.PI) / .3) + 1; + }; + /*\ + * mina.bounce + [ method ] + ** + * Bounce easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.bounce = function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + }; + window.mina = mina; + return mina; +})(typeof eve == "undefined" ? function () {} : eve); +// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var Snap = (function(root) { +Snap.version = "0.4.0"; +/*\ + * Snap + [ method ] + ** + * Creates a drawing surface or wraps existing SVG element. + ** + - width (number|string) width of surface + - height (number|string) height of surface + * or + - DOM (SVGElement) element to be wrapped into Snap structure + * or + - array (array) array of elements (will return set of elements) + * or + - query (string) CSS query selector + = (object) @Element +\*/ +function Snap(w, h) { + if (w) { + if (w.nodeType) { + return wrap(w); + } + if (is(w, "array") && Snap.set) { + return Snap.set.apply(Snap, w); + } + if (w instanceof Element) { + return w; + } + if (h == null) { + w = glob.doc.querySelector(String(w)); + return wrap(w); + } + } + w = w == null ? "100%" : w; + h = h == null ? "100%" : h; + return new Paper(w, h); +} +Snap.toString = function () { + return "Snap v" + this.version; +}; +Snap._ = {}; +var glob = { + win: root.window, + doc: root.window.document +}; +Snap._.glob = glob; +var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + round = math.round, + E = "", + S = " ", + objectToString = Object.prototype.toString, + ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + reURLValue = /^url\(#?([^)]+)\)$/, + separator = Snap._.separator = /[,\s]+/, + whitespace = /[\s]/g, + commaSpaces = /[\s]*,[\s]*/, + hsrg = {hs: 1, rg: 1}, + pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig, + idgen = 0, + idprefix = "S" + (+new Date).toString(36), + ID = function (el) { + return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36); + }, + xlink = "http://www.w3.org/1999/xlink", + xmlns = "http://www.w3.org/2000/svg", + hub = {}, + URL = Snap.url = function (url) { + return "url('#" + url + "')"; + }; + +function $(el, attr) { + if (attr) { + if (el == "#text") { + el = glob.doc.createTextNode(attr.text || attr["#text"] || ""); + } + if (el == "#comment") { + el = glob.doc.createComment(attr.text || attr["#text"] || ""); + } + if (typeof el == "string") { + el = $(el); + } + if (typeof attr == "string") { + if (el.nodeType == 1) { + if (attr.substring(0, 6) == "xlink:") { + return el.getAttributeNS(xlink, attr.substring(6)); + } + if (attr.substring(0, 4) == "xml:") { + return el.getAttributeNS(xmlns, attr.substring(4)); + } + return el.getAttribute(attr); + } else if (attr == "text") { + return el.nodeValue; + } else { + return null; + } + } + if (el.nodeType == 1) { + for (var key in attr) if (attr[has](key)) { + var val = Str(attr[key]); + if (val) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), val); + } else if (key.substring(0, 4) == "xml:") { + el.setAttributeNS(xmlns, key.substring(4), val); + } else { + el.setAttribute(key, val); + } + } else { + el.removeAttribute(key); + } + } + } else if ("text" in attr) { + el.nodeValue = attr.text; + } + } else { + el = glob.doc.createElementNS(xmlns, el); + } + return el; +} +Snap._.$ = $; +Snap._.id = ID; +function getAttrs(el) { + var attrs = el.attributes, + name, + out = {}; + for (var i = 0; i < attrs.length; i++) { + if (attrs[i].namespaceURI == xlink) { + name = "xlink:"; + } else { + name = ""; + } + name += attrs[i].name; + out[name] = attrs[i].textContent; + } + return out; +} +function is(o, type) { + type = Str.prototype.toLowerCase.call(type); + if (type == "finite") { + return isFinite(o); + } + if (type == "array" && + (o instanceof Array || Array.isArray && Array.isArray(o))) { + return true; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; +} +/*\ + * Snap.format + [ method ] + ** + * Replaces construction of type `{<name>}` to the corresponding argument + ** + - token (string) string to format + - json (object) object which properties are used as a replacement + = (string) formatted string + > Usage + | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z" + | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { + | x: 10, + | y: 20, + | dim: { + | width: 40, + | height: 50, + | "negative width": -40 + | } + | })); +\*/ +Snap.format = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return Str(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; +})(); +function clone(obj) { + if (typeof obj == "function" || Object(obj) !== obj) { + return obj; + } + var res = new obj.constructor; + for (var key in obj) if (obj[has](key)) { + res[key] = clone(obj[key]); + } + return res; +} +Snap._.clone = clone; +function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } +} +function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f.apply(scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; +} +Snap._.cacher = cacher; +function angle(x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3); + } +} +function rad(deg) { + return deg % 360 * PI / 180; +} +function deg(rad) { + return rad * 180 / PI % 360; +} +function x_y() { + return this.x + S + this.y; +} +function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; +} + +/*\ + * Snap.rad + [ method ] + ** + * Transform angle to radians + - deg (number) angle in degrees + = (number) angle in radians +\*/ +Snap.rad = rad; +/*\ + * Snap.deg + [ method ] + ** + * Transform angle to degrees + - rad (number) angle in radians + = (number) angle in degrees +\*/ +Snap.deg = deg; +/*\ + * Snap.sin + [ method ] + ** + * Equivalent to `Math.sin()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) sin +\*/ +Snap.sin = function (angle) { + return math.sin(Snap.rad(angle)); +}; +/*\ + * Snap.tan + [ method ] + ** + * Equivalent to `Math.tan()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) tan +\*/ +Snap.tan = function (angle) { + return math.tan(Snap.rad(angle)); +}; +/*\ + * Snap.cos + [ method ] + ** + * Equivalent to `Math.cos()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) cos +\*/ +Snap.cos = function (angle) { + return math.cos(Snap.rad(angle)); +}; +/*\ + * Snap.asin + [ method ] + ** + * Equivalent to `Math.asin()` only works with degrees, not radians. + - num (number) value + = (number) asin in degrees +\*/ +Snap.asin = function (num) { + return Snap.deg(math.asin(num)); +}; +/*\ + * Snap.acos + [ method ] + ** + * Equivalent to `Math.acos()` only works with degrees, not radians. + - num (number) value + = (number) acos in degrees +\*/ +Snap.acos = function (num) { + return Snap.deg(math.acos(num)); +}; +/*\ + * Snap.atan + [ method ] + ** + * Equivalent to `Math.atan()` only works with degrees, not radians. + - num (number) value + = (number) atan in degrees +\*/ +Snap.atan = function (num) { + return Snap.deg(math.atan(num)); +}; +/*\ + * Snap.atan2 + [ method ] + ** + * Equivalent to `Math.atan2()` only works with degrees, not radians. + - num (number) value + = (number) atan2 in degrees +\*/ +Snap.atan2 = function (num) { + return Snap.deg(math.atan2(num)); +}; +/*\ + * Snap.angle + [ method ] + ** + * Returns an angle between two or three points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + - x3 (number) #optional x coord of third point + - y3 (number) #optional y coord of third point + = (number) angle in degrees +\*/ +Snap.angle = angle; +/*\ + * Snap.len + [ method ] + ** + * Returns distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len = function (x1, y1, x2, y2) { + return Math.sqrt(Snap.len2(x1, y1, x2, y2)); +}; +/*\ + * Snap.len2 + [ method ] + ** + * Returns squared distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len2 = function (x1, y1, x2, y2) { + return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); +}; +/*\ + * Snap.closestPoint + [ method ] + ** + * Returns closest point to a given one on a given path. + > Parameters + - path (Element) path element + - x (number) x coord of a point + - y (number) y coord of a point + = (object) in format + { + x (number) x coord of the point on the path + y (number) y coord of the point on the path + length (number) length of the path to the point + distance (number) distance from the given point to the path + } +\*/ +// Copied from http://bl.ocks.org/mbostock/8027637 +Snap.closestPoint = function (path, x, y) { + function distance2(p) { + var dx = p.x - x, + dy = p.y - y; + return dx * dx + dy * dy; + } + var pathNode = path.node, + pathLength = pathNode.getTotalLength(), + precision = pathLength / pathNode.pathSegList.numberOfItems * .125, + best, + bestLength, + bestDistance = Infinity; + + // linear scan for coarse approximation + for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { + if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) { + best = scan, bestLength = scanLength, bestDistance = scanDistance; + } + } + + // binary search for precise estimate + precision *= .5; + while (precision > .5) { + var before, + after, + beforeLength, + afterLength, + beforeDistance, + afterDistance; + if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) { + best = before, bestLength = beforeLength, bestDistance = beforeDistance; + } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) { + best = after, bestLength = afterLength, bestDistance = afterDistance; + } else { + precision *= .5; + } + } + + best = { + x: best.x, + y: best.y, + length: bestLength, + distance: Math.sqrt(bestDistance) + }; + return best; +} +/*\ + * Snap.is + [ method ] + ** + * Handy replacement for the `typeof` operator + - o (…) any object or primitive + - type (string) name of the type, e.g., `string`, `function`, `number`, etc. + = (boolean) `true` if given value is of given type +\*/ +Snap.is = is; +/*\ + * Snap.snapTo + [ method ] + ** + * Snaps given value to given grid + - values (array|number) given array of values or step of the grid + - value (number) value to adjust + - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`. + = (number) adjusted value +\*/ +Snap.snapTo = function (values, value, tolerance) { + tolerance = is(tolerance, "finite") ? tolerance : 10; + if (is(values, "array")) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; +}; +// Colour +/*\ + * Snap.getRGB + [ method ] + ** + * Parses color string as RGB object + - color (string) color string in one of the following formats: + # <ul> + # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li> + # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li> + # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li> + # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li> + # <li>rgba(•••, •••, •••, •••) — also with opacity</li> + # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li> + # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li> + # <li>hsba(•••, •••, •••, •••) — also with opacity</li> + # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li> + # <li>hsla(•••, •••, •••, •••) — also with opacity</li> + # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li> + # </ul> + * Note that `%` can be used any time: `rgb(20%, 255, 50%)`. + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) true if string can't be parsed + o } +\*/ +Snap.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + if (!colour) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsl2rgb(red, green, blue, opacity); + } + red = mmin(math.round(red), 255); + green = mmin(math.round(green), 255); + blue = mmin(math.round(blue), 255); + opacity = mmin(mmax(opacity, 0), 1); + rgb = {r: red, g: green, b: blue, toString: rgbtoString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + rgb.opacity = is(opacity, "finite") ? opacity : 1; + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; +}, Snap); +/*\ + * Snap.hsb + [ method ] + ** + * Converts HSB values to a hex representation of the color + - h (number) hue + - s (number) saturation + - b (number) value or brightness + = (string) hex representation of the color +\*/ +Snap.hsb = cacher(function (h, s, b) { + return Snap.hsb2rgb(h, s, b).hex; +}); +/*\ + * Snap.hsl + [ method ] + ** + * Converts HSL values to a hex representation of the color + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (string) hex representation of the color +\*/ +Snap.hsl = cacher(function (h, s, l) { + return Snap.hsl2rgb(h, s, l).hex; +}); +/*\ + * Snap.rgb + [ method ] + ** + * Converts RGB values to a hex representation of the color + - r (number) red + - g (number) green + - b (number) blue + = (string) hex representation of the color +\*/ +Snap.rgb = cacher(function (r, g, b, o) { + if (is(o, "finite")) { + var round = math.round; + return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")"; + } + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); +}); +var toHex = function (color) { + var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0], + red = "rgb(255, 0, 0)"; + toHex = cacher(function (color) { + if (color.toLowerCase() == "red") { + return red; + } + i.style.color = red; + i.style.color = color; + var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + return out == red ? null : out; + }); + return toHex(color); +}, +hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; +}, +hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; +}, +rgbtoString = function () { + return this.opacity == 1 || this.opacity == null ? + this.hex : + "rgba(" + [this.r, this.g, this.b, this.opacity] + ")"; +}, +prepareRGB = function (r, g, b) { + if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && is(r, string)) { + var clr = Snap.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; +}, +packageRGB = function (r, g, b, o) { + r = math.round(r * 255); + g = math.round(g * 255); + b = math.round(b * 255); + var rgb = { + r: r, + g: g, + b: b, + opacity: is(o, "finite") ? o : 1, + hex: Snap.rgb(r, g, b), + toString: rgbtoString + }; + is(o, "finite") && (rgb.opacity = o); + return rgb; +}; +/*\ + * Snap.color + [ method ] + ** + * Parses the color string and returns an object featuring the color's component values + - clr (string) color string in one of the supported formats (see @Snap.getRGB) + = (object) Combined RGB/HSB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) `true` if string can't be parsed, + o h (number) hue, + o s (number) saturation, + o v (number) value (brightness), + o l (number) lightness + o } +\*/ +Snap.color = function (clr) { + var rgb; + if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = Snap.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = Snap.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else { + if (is(clr, "string")) { + clr = Snap.getRGB(clr); + } + if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) { + rgb = Snap.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = Snap.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + clr.error = 1; + } + } + clr.toString = rgbtoString; + return clr; +}; +/*\ + * Snap.hsb2rgb + [ method ] + ** + * Converts HSB values to an RGB object + - h (number) hue + - s (number) saturation + - v (number) value or brightness + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsb2rgb = function (h, s, v, o) { + if (is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + o = h.o; + h = h.h; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.hsl2rgb + [ method ] + ** + * Converts HSL values to an RGB object + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsl2rgb = function (h, s, l, o) { + if (is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.rgb2hsb + [ method ] + ** + * Converts RGB values to an HSB object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSB object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o b (number) brightness + o } +\*/ +Snap.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; +}; +/*\ + * Snap.rgb2hsl + [ method ] + ** + * Converts RGB values to an HSL object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSL object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o l (number) luminosity + o } +\*/ +Snap.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; +}; + +// Transformations +/*\ + * Snap.parsePathString + [ method ] + ** + * Utility method + ** + * Parses given path string into an array of arrays of path segments + - pathString (string|array) path string or array of segments (in the last case it is returned straight away) + = (array) array of segments +\*/ +Snap.parsePathString = function (pathString) { + if (!pathString) { + return null; + } + var pth = Snap.path(pathString); + if (pth.arr) { + return Snap.path.clone(pth.arr); + } + + var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0}, + data = []; + if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption + data = Snap.path.clone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b].concat(params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "o" && params.length == 1) { + data.push([b, params[0]]); + } + if (name == "r") { + data.push([b].concat(params)); + } else while (params.length >= paramCounts[name]) { + data.push([b].concat(params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = Snap.path.toString; + pth.arr = Snap.path.clone(data); + return data; +}; +/*\ + * Snap.parseTransformString + [ method ] + ** + * Utility method + ** + * Parses given transform string into an array of transformations + - TString (string|array) transform string or array of transformations (in the last case it is returned straight away) + = (array) array of transformations +\*/ +var parseTransformString = Snap.parseTransformString = function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (is(TString, "array") && is(TString[0], "array")) { // rough assumption + data = Snap.path.clone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b].concat(params)); + }); + } + data.toString = Snap.path.toString; + return data; +}; +function svgTransform2string(tstr) { + var res = []; + tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) { + params = params.split(/\s*,\s*|\s+/); + if (name == "rotate" && params.length == 1) { + params.push(0, 0); + } + if (name == "scale") { + if (params.length > 2) { + params = params.slice(0, 2); + } else if (params.length == 2) { + params.push(0, 0); + } + if (params.length == 1) { + params.push(params[0], 0, 0); + } + } + if (name == "skewX") { + res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]); + } else if (name == "skewY") { + res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]); + } else { + res.push([name.charAt(0)].concat(params)); + } + return all; + }); + return res; +} +Snap._.svgTransform2string = svgTransform2string; +Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i; +function transform2matrix(tstr, bbox) { + var tdata = parseTransformString(tstr), + m = new Snap.Matrix; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 2){ + m.translate(t[1], 0); + } else if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || bbox; + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || bbox; + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.scale(t[1], t[1], x2, y2); + } else { + m.scale(t[1], t[1], t[2], t[3]); + } + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + } + } + return m; +} +Snap._.transform2matrix = transform2matrix; +Snap._unit2px = unit2px; +var contains = glob.doc.contains || glob.doc.compareDocumentPosition ? + function (a, b) { + var adown = a.nodeType == 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a == bup || !!(bup && bup.nodeType == 1 && ( + adown.contains ? + adown.contains(bup) : + a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16 + )); + } : + function (a, b) { + if (b) { + while (b) { + b = b.parentNode; + if (b == a) { + return true; + } + } + } + return false; + }; +function getSomeDefs(el) { + var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) || + (el.node.parentNode && wrap(el.node.parentNode)) || + Snap.select("svg") || + Snap(0, 0), + pdefs = p.select("defs"), + defs = pdefs == null ? false : pdefs.node; + if (!defs) { + defs = make("defs", p.node).node; + } + return defs; +} +function getSomeSVG(el) { + return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg"); +} +Snap._.getSomeDefs = getSomeDefs; +Snap._.getSomeSVG = getSomeSVG; +function unit2px(el, name, value) { + var svg = getSomeSVG(el).node, + out = {}, + mgr = svg.querySelector(".svg---mgr"); + if (!mgr) { + mgr = $("rect"); + $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"}); + svg.appendChild(mgr); + } + function getW(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {width: val}); + try { + return mgr.getBBox().width; + } catch (e) { + return 0; + } + } + function getH(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {height: val}); + try { + return mgr.getBBox().height; + } catch (e) { + return 0; + } + } + function set(nam, f) { + if (name == null) { + out[nam] = f(el.attr(nam) || 0); + } else if (nam == name) { + out = f(value == null ? el.attr(nam) || 0 : value); + } + } + switch (el.type) { + case "rect": + set("rx", getW); + set("ry", getH); + case "image": + set("width", getW); + set("height", getH); + case "text": + set("x", getW); + set("y", getH); + break; + case "circle": + set("cx", getW); + set("cy", getH); + set("r", getW); + break; + case "ellipse": + set("cx", getW); + set("cy", getH); + set("rx", getW); + set("ry", getH); + break; + case "line": + set("x1", getW); + set("x2", getW); + set("y1", getH); + set("y2", getH); + break; + case "marker": + set("refX", getW); + set("markerWidth", getW); + set("refY", getH); + set("markerHeight", getH); + break; + case "radialGradient": + set("fx", getW); + set("fy", getH); + break; + case "tspan": + set("dx", getW); + set("dy", getH); + break; + default: + set(name, getW); + } + svg.removeChild(mgr); + return out; +} +/*\ + * Snap.select + [ method ] + ** + * Wraps a DOM element specified by CSS selector as @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.select = function (query) { + query = Str(query).replace(/([^\\]):/g, "$1\\:"); + return wrap(glob.doc.querySelector(query)); +}; +/*\ + * Snap.selectAll + [ method ] + ** + * Wraps DOM elements specified by CSS selector as set or array of @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.selectAll = function (query) { + var nodelist = glob.doc.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; +}; + +function add2group(list) { + if (!is(list, "array")) { + list = Array.prototype.slice.call(arguments, 0); + } + var i = 0, + j = 0, + node = this.node; + while (this[i]) delete this[i++]; + for (i = 0; i < list.length; i++) { + if (list[i].type == "set") { + list[i].forEach(function (el) { + node.appendChild(el.node); + }); + } else { + node.appendChild(list[i].node); + } + } + var children = node.childNodes; + for (i = 0; i < children.length; i++) { + this[j++] = wrap(children[i]); + } + return this; +} +// Hub garbage collector every 10s +setInterval(function () { + for (var key in hub) if (hub[has](key)) { + var el = hub[key], + node = el.node; + if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) { + delete hub[key]; + } + } +}, 1e4); +function Element(el) { + if (el.snap in hub) { + return hub[el.snap]; + } + var svg; + try { + svg = el.ownerSVGElement; + } catch(e) {} + /*\ + * Element.node + [ property (object) ] + ** + * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. + > Usage + | // draw a circle at coordinate 10,10 with radius of 10 + | var c = paper.circle(10, 10, 10); + | c.node.onclick = function () { + | c.attr("fill", "red"); + | }; + \*/ + this.node = el; + if (svg) { + this.paper = new Paper(svg); + } + /*\ + * Element.type + [ property (string) ] + ** + * SVG tag name of the given element. + \*/ + this.type = el.tagName || el.nodeName; + var id = this.id = ID(this); + this.anims = {}; + this._ = { + transform: [] + }; + el.snap = id; + hub[id] = this; + if (this.type == "g") { + this.add = add2group; + } + if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) { + for (var method in Paper.prototype) if (Paper.prototype[has](method)) { + this[method] = Paper.prototype[method]; + } + } +} + /*\ + * Element.attr + [ method ] + ** + * Gets or sets given attributes of the element. + ** + - params (object) contains key-value pairs of attributes you want to set + * or + - param (string) name of the attribute + = (Element) the current element + * or + = (string) value of attribute + > Usage + | el.attr({ + | fill: "#fc0", + | stroke: "#000", + | strokeWidth: 2, // CamelCase... + | "fill-opacity": 0.5, // or dash-separated names + | width: "*=2" // prefixed values + | }); + | console.log(el.attr("fill")); // #fc0 + * Prefixed values in format `"+=10"` supported. All four operations + * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+` + * and `-`: `"+=2em"`. + \*/ + Element.prototype.attr = function (params, value) { + var el = this, + node = el.node; + if (!params) { + if (node.nodeType != 1) { + return { + text: node.nodeValue + }; + } + var attr = node.attributes, + out = {}; + for (var i = 0, ii = attr.length; i < ii; i++) { + out[attr[i].nodeName] = attr[i].nodeValue; + } + return out; + } + if (is(params, "string")) { + if (arguments.length > 1) { + var json = {}; + json[params] = value; + params = json; + } else { + return eve("snap.util.getattr." + params, el).firstDefined(); + } + } + for (var att in params) { + if (params[has](att)) { + eve("snap.util.attr." + att, el, params[att]); + } + } + return el; + }; +/*\ + * Snap.parse + [ method ] + ** + * Parses SVG fragment and converts it into a @Fragment + ** + - svg (string) SVG string + = (Fragment) the @Fragment +\*/ +Snap.parse = function (svg) { + var f = glob.doc.createDocumentFragment(), + full = true, + div = glob.doc.createElement("div"); + svg = Str(svg); + if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) { + svg = "<svg>" + svg + "</svg>"; + full = false; + } + div.innerHTML = svg; + svg = div.getElementsByTagName("svg")[0]; + if (svg) { + if (full) { + f = svg; + } else { + while (svg.firstChild) { + f.appendChild(svg.firstChild); + } + } + } + return new Fragment(f); +}; +function Fragment(frag) { + this.node = frag; +} +/*\ + * Snap.fragment + [ method ] + ** + * Creates a DOM fragment from a given list of elements or strings + ** + - varargs (…) SVG string + = (Fragment) the @Fragment +\*/ +Snap.fragment = function () { + var args = Array.prototype.slice.call(arguments, 0), + f = glob.doc.createDocumentFragment(); + for (var i = 0, ii = args.length; i < ii; i++) { + var item = args[i]; + if (item.node && item.node.nodeType) { + f.appendChild(item.node); + } + if (item.nodeType) { + f.appendChild(item); + } + if (typeof item == "string") { + f.appendChild(Snap.parse(item).node); + } + } + return new Fragment(f); +}; + +function make(name, parent) { + var res = $(name); + parent.appendChild(res); + var el = wrap(res); + return el; +} +function Paper(w, h) { + var res, + desc, + defs, + proto = Paper.prototype; + if (w && w.tagName == "svg") { + if (w.snap in hub) { + return hub[w.snap]; + } + var doc = w.ownerDocument; + res = new Element(w); + desc = w.getElementsByTagName("desc")[0]; + defs = w.getElementsByTagName("defs")[0]; + if (!desc) { + desc = $("desc"); + desc.appendChild(doc.createTextNode("Created with Snap")); + res.node.appendChild(desc); + } + if (!defs) { + defs = $("defs"); + res.node.appendChild(defs); + } + res.defs = defs; + for (var key in proto) if (proto[has](key)) { + res[key] = proto[key]; + } + res.paper = res.root = res; + } else { + res = make("svg", glob.doc.body); + $(res.node, { + height: h, + version: 1.1, + width: w, + xmlns: xmlns + }); + } + return res; +} +function wrap(dom) { + if (!dom) { + return dom; + } + if (dom instanceof Element || dom instanceof Fragment) { + return dom; + } + if (dom.tagName && dom.tagName.toLowerCase() == "svg") { + return new Paper(dom); + } + if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") { + return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]); + } + return new Element(dom); +} + +Snap._.make = make; +Snap._.wrap = wrap; +/*\ + * Paper.el + [ method ] + ** + * Creates an element on paper with a given name and no attributes + ** + - name (string) tag name + - attr (object) attributes + = (Element) the current element + > Usage + | var c = paper.circle(10, 10, 10); // is the same as... + | var c = paper.el("circle").attr({ + | cx: 10, + | cy: 10, + | r: 10 + | }); + | // and the same as + | var c = paper.el("circle", { + | cx: 10, + | cy: 10, + | r: 10 + | }); +\*/ +Paper.prototype.el = function (name, attr) { + var el = make(name, this.node); + attr && el.attr(attr); + return el; +}; +/*\ + * Element.children + [ method ] + ** + * Returns array of all the children of the element. + = (array) array of Elements +\*/ +Element.prototype.children = function () { + var out = [], + ch = this.node.childNodes; + for (var i = 0, ii = ch.length; i < ii; i++) { + out[i] = Snap(ch[i]); + } + return out; +}; +function jsonFiller(root, o) { + for (var i = 0, ii = root.length; i < ii; i++) { + var item = { + type: root[i].type, + attr: root[i].attr() + }, + children = root[i].children(); + o.push(item); + if (children.length) { + jsonFiller(children, item.childNodes = []); + } + } +} +/*\ + * Element.toJSON + [ method ] + ** + * Returns object representation of the given element and all its children. + = (object) in format + o { + o type (string) this.type, + o attr (object) attributes map, + o childNodes (array) optional array of children in the same format + o } +\*/ +Element.prototype.toJSON = function () { + var out = []; + jsonFiller([this], out); + return out[0]; +}; +// default +eve.on("snap.util.getattr", function () { + var att = eve.nt(); + att = att.substring(att.lastIndexOf(".") + 1); + var css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css); + } else { + return $(this.node, att); + } +}); +var cssAttr = { + "alignment-baseline": 0, + "baseline-shift": 0, + "clip": 0, + "clip-path": 0, + "clip-rule": 0, + "color": 0, + "color-interpolation": 0, + "color-interpolation-filters": 0, + "color-profile": 0, + "color-rendering": 0, + "cursor": 0, + "direction": 0, + "display": 0, + "dominant-baseline": 0, + "enable-background": 0, + "fill": 0, + "fill-opacity": 0, + "fill-rule": 0, + "filter": 0, + "flood-color": 0, + "flood-opacity": 0, + "font": 0, + "font-family": 0, + "font-size": 0, + "font-size-adjust": 0, + "font-stretch": 0, + "font-style": 0, + "font-variant": 0, + "font-weight": 0, + "glyph-orientation-horizontal": 0, + "glyph-orientation-vertical": 0, + "image-rendering": 0, + "kerning": 0, + "letter-spacing": 0, + "lighting-color": 0, + "marker": 0, + "marker-end": 0, + "marker-mid": 0, + "marker-start": 0, + "mask": 0, + "opacity": 0, + "overflow": 0, + "pointer-events": 0, + "shape-rendering": 0, + "stop-color": 0, + "stop-opacity": 0, + "stroke": 0, + "stroke-dasharray": 0, + "stroke-dashoffset": 0, + "stroke-linecap": 0, + "stroke-linejoin": 0, + "stroke-miterlimit": 0, + "stroke-opacity": 0, + "stroke-width": 0, + "text-anchor": 0, + "text-decoration": 0, + "text-rendering": 0, + "unicode-bidi": 0, + "visibility": 0, + "word-spacing": 0, + "writing-mode": 0 +}; + +eve.on("snap.util.attr", function (value) { + var att = eve.nt(), + attr = {}; + att = att.substring(att.lastIndexOf(".") + 1); + attr[att] = value; + var style = att.replace(/-(\w)/gi, function (all, letter) { + return letter.toUpperCase(); + }), + css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + this.node.style[style] = value == null ? E : value; + } else { + $(this.node, attr); + } +}); +(function (proto) {}(Paper.prototype)); + +// simple ajax +/*\ + * Snap.ajax + [ method ] + ** + * Simple implementation of Ajax + ** + - url (string) URL + - postData (object|string) data for post request + - callback (function) callback + - scope (object) #optional scope of callback + * or + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback + = (XMLHttpRequest) the XMLHttpRequest object, just in case +\*/ +Snap.ajax = function (url, postData, callback, scope){ + var req = new XMLHttpRequest, + id = ID(); + if (req) { + if (is(postData, "function")) { + scope = callback; + callback = postData; + postData = null; + } else if (is(postData, "object")) { + var pd = []; + for (var key in postData) if (postData.hasOwnProperty(key)) { + pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key])); + } + postData = pd.join("&"); + } + req.open((postData ? "POST" : "GET"), url, true); + if (postData) { + req.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + if (callback) { + eve.once("snap.ajax." + id + ".0", callback); + eve.once("snap.ajax." + id + ".200", callback); + eve.once("snap.ajax." + id + ".304", callback); + } + req.onreadystatechange = function() { + if (req.readyState != 4) return; + eve("snap.ajax." + id + "." + req.status, scope, req); + }; + if (req.readyState == 4) { + return req; + } + req.send(postData); + return req; + } +}; +/*\ + * Snap.load + [ method ] + ** + * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX) + ** + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback +\*/ +Snap.load = function (url, callback, scope) { + Snap.ajax(url, function (req) { + var f = Snap.parse(req.responseText); + scope ? callback.call(scope, f) : callback(f); + }); +}; +var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; +}; +/*\ + * Snap.getElementByPoint + [ method ] + ** + * Returns you topmost element under given point. + ** + = (object) Snap element object + - x (number) x coordinate from the top left corner of the window + - y (number) y coordinate from the top left corner of the window + > Usage + | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); +\*/ +Snap.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = glob.doc.elementFromPoint(x, y); + if (glob.win.opera && target.tagName == "svg") { + var so = getOffset(target), + sr = target.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = target.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + return wrap(target); +}; +/*\ + * Snap.plugin + [ method ] + ** + * Let you write plugins. You pass in a function with five arguments, like this: + | Snap.plugin(function (Snap, Element, Paper, global, Fragment) { + | Snap.newmethod = function () {}; + | Element.prototype.newmethod = function () {}; + | Paper.prototype.newmethod = function () {}; + | }); + * Inside the function you have access to all main objects (and their + * prototypes). This allow you to extend anything you want. + ** + - f (function) your plugin body +\*/ +Snap.plugin = function (f) { + f(Snap, Element, Paper, glob, Fragment); +}; +glob.win.Snap = Snap; +return Snap; +}(window || this)); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var elproto = Element.prototype, + is = Snap.is, + Str = String, + unit2px = Snap._unit2px, + $ = Snap._.$, + make = Snap._.make, + getSomeDefs = Snap._.getSomeDefs, + has = "hasOwnProperty", + wrap = Snap._.wrap; + /*\ + * Element.getBBox + [ method ] + ** + * Returns the bounding box descriptor for the given element + ** + = (object) bounding box descriptor: + o { + o cx: (number) x of the center, + o cy: (number) x of the center, + o h: (number) height, + o height: (number) height, + o path: (string) path command for the box, + o r0: (number) radius of a circle that fully encloses the box, + o r1: (number) radius of the smallest circle that can be enclosed, + o r2: (number) radius of the largest circle that can be enclosed, + o vb: (string) box as a viewbox command, + o w: (number) width, + o width: (number) width, + o x2: (number) x of the right side, + o x: (number) x of the left side, + o y2: (number) y of the bottom edge, + o y: (number) y of the top edge + o } + \*/ + elproto.getBBox = function (isWithoutTransform) { + if (!Snap.Matrix || !Snap.path) { + return this.node.getBBox(); + } + var el = this, + m = new Snap.Matrix; + if (el.removed) { + return Snap._.box(); + } + while (el.type == "use") { + if (!isWithoutTransform) { + m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0)); + } + if (el.original) { + el = el.original; + } else { + var href = el.attr("xlink:href"); + el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1)); + } + } + var _ = el._, + pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt; + try { + if (isWithoutTransform) { + _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox()); + return Snap._.box(_.bboxwt); + } else { + el.realPath = pathfinder(el); + el.matrix = el.transform().localMatrix; + _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix))); + return Snap._.box(_.bbox); + } + } catch (e) { + // Firefox doesn’t give you bbox of hidden element + return Snap._.box(); + } + }; + var propString = function () { + return this.string; + }; + function extractTransform(el, tstr) { + if (tstr == null) { + var doReturn = true; + if (el.type == "linearGradient" || el.type == "radialGradient") { + tstr = el.node.getAttribute("gradientTransform"); + } else if (el.type == "pattern") { + tstr = el.node.getAttribute("patternTransform"); + } else { + tstr = el.node.getAttribute("transform"); + } + if (!tstr) { + return new Snap.Matrix; + } + tstr = Snap._.svgTransform2string(tstr); + } else { + if (!Snap._.rgTransform.test(tstr)) { + tstr = Snap._.svgTransform2string(tstr); + } else { + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || ""); + } + if (is(tstr, "array")) { + tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr); + } + el._.transform = tstr; + } + var m = Snap._.transform2matrix(tstr, el.getBBox(1)); + if (doReturn) { + return m; + } else { + el.matrix = m; + } + } + /*\ + * Element.transform + [ method ] + ** + * Gets or sets transformation of the element + ** + - tstr (string) transform string in Snap or SVG format + = (Element) the current element + * or + = (object) transformation descriptor: + o { + o string (string) transform string, + o globalMatrix (Matrix) matrix of all transformations applied to element or its parents, + o localMatrix (Matrix) matrix of transformations applied only to the element, + o diffMatrix (Matrix) matrix of difference between global and local transformations, + o global (string) global transformation as string, + o local (string) local transformation as string, + o toString (function) returns `string` property + o } + \*/ + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + var papa = this, + global = new Snap.Matrix(this.node.getCTM()), + local = extractTransform(this), + ms = [local], + m = new Snap.Matrix, + i, + localString = local.toTransformString(), + string = Str(local) == Str(this.matrix) ? + Str(_.transform) : localString; + while (papa.type != "svg" && (papa = papa.parent())) { + ms.push(extractTransform(papa)); + } + i = ms.length; + while (i--) { + m.add(ms[i]); + } + return { + string: string, + globalMatrix: global, + totalMatrix: m, + localMatrix: local, + diffMatrix: global.clone().add(local.invert()), + global: global.toTransformString(), + total: m.toTransformString(), + local: localString, + toString: propString + }; + } + if (tstr instanceof Snap.Matrix) { + this.matrix = tstr; + this._.transform = tstr.toTransformString(); + } else { + extractTransform(this, tstr); + } + + if (this.node) { + if (this.type == "linearGradient" || this.type == "radialGradient") { + $(this.node, {gradientTransform: this.matrix}); + } else if (this.type == "pattern") { + $(this.node, {patternTransform: this.matrix}); + } else { + $(this.node, {transform: this.matrix}); + } + } + + return this; + }; + /*\ + * Element.parent + [ method ] + ** + * Returns the element's parent + ** + = (Element) the parent element + \*/ + elproto.parent = function () { + return wrap(this.node.parentNode); + }; + /*\ + * Element.append + [ method ] + ** + * Appends the given element to current one + ** + - el (Element|Set) element to append + = (Element) the parent element + \*/ + /*\ + * Element.add + [ method ] + ** + * See @Element.append + \*/ + elproto.append = elproto.add = function (el) { + if (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + it.add(el); + }); + return this; + } + el = wrap(el); + this.node.appendChild(el.node); + el.paper = this.paper; + } + return this; + }; + /*\ + * Element.appendTo + [ method ] + ** + * Appends the current element to the given one + ** + - el (Element) parent element to append to + = (Element) the child element + \*/ + elproto.appendTo = function (el) { + if (el) { + el = wrap(el); + el.append(this); + } + return this; + }; + /*\ + * Element.prepend + [ method ] + ** + * Prepends the given element to the current one + ** + - el (Element) element to prepend + = (Element) the parent element + \*/ + elproto.prepend = function (el) { + if (el) { + if (el.type == "set") { + var it = this, + first; + el.forEach(function (el) { + if (first) { + first.after(el); + } else { + it.prepend(el); + } + first = el; + }); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.insertBefore(el.node, this.node.firstChild); + this.add && this.add(); + el.paper = this.paper; + this.parent() && this.parent().add(); + parent && parent.add(); + } + return this; + }; + /*\ + * Element.prependTo + [ method ] + ** + * Prepends the current element to the given one + ** + - el (Element) parent element to prepend to + = (Element) the child element + \*/ + elproto.prependTo = function (el) { + el = wrap(el); + el.prepend(this); + return this; + }; + /*\ + * Element.before + [ method ] + ** + * Inserts given element before the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.before = function (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + var parent = el.parent(); + it.node.parentNode.insertBefore(el.node, it.node); + parent && parent.add(); + }); + this.parent().add(); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.parentNode.insertBefore(el.node, this.node); + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.after + [ method ] + ** + * Inserts given element after the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.after = function (el) { + el = wrap(el); + var parent = el.parent(); + if (this.node.nextSibling) { + this.node.parentNode.insertBefore(el.node, this.node.nextSibling); + } else { + this.node.parentNode.appendChild(el.node); + } + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.insertBefore + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertBefore = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.insertAfter + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertAfter = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node.nextSibling); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.remove + [ method ] + ** + * Removes element from the DOM + = (Element) the detached element + \*/ + elproto.remove = function () { + var parent = this.parent(); + this.node.parentNode && this.node.parentNode.removeChild(this.node); + delete this.paper; + this.removed = true; + parent && parent.add(); + return this; + }; + /*\ + * Element.select + [ method ] + ** + * Gathers the nested @Element matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Element) result of query selection + \*/ + elproto.select = function (query) { + return wrap(this.node.querySelector(query)); + }; + /*\ + * Element.selectAll + [ method ] + ** + * Gathers nested @Element objects matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Set|array) result of query selection + \*/ + elproto.selectAll = function (query) { + var nodelist = this.node.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; + }; + /*\ + * Element.asPX + [ method ] + ** + * Returns given attribute of the element as a `px` value (not %, em, etc.) + ** + - attr (string) attribute name + - value (string) #optional attribute value + = (Element) result of query selection + \*/ + elproto.asPX = function (attr, value) { + if (value == null) { + value = this.attr(attr); + } + return +unit2px(this, attr, value); + }; + // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar. + /*\ + * Element.use + [ method ] + ** + * Creates a `<use>` element linked to the current element + ** + = (Element) the `<use>` element + \*/ + elproto.use = function () { + var use, + id = this.node.id; + if (!id) { + id = this.id; + $(this.node, { + id: id + }); + } + if (this.type == "linearGradient" || this.type == "radialGradient" || + this.type == "pattern") { + use = make(this.type, this.node.parentNode); + } else { + use = make("use", this.node.parentNode); + } + $(use.node, { + "xlink:href": "#" + id + }); + use.original = this; + return use; + }; + function fixids(el) { + var els = el.selectAll("*"), + it, + url = /^\s*url\(("|'|)(.*)\1\)\s*$/, + ids = [], + uses = {}; + function urltest(it, name) { + var val = $(it.node, name); + val = val && val.match(url); + val = val && val[2]; + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + var attr = {}; + attr[name] = URL(id); + $(it.node, attr); + }); + } + } + function linktest(it) { + var val = $(it.node, "xlink:href"); + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + it.attr("xlink:href", "#" + id); + }); + } + } + for (var i = 0, ii = els.length; i < ii; i++) { + it = els[i]; + urltest(it, "fill"); + urltest(it, "stroke"); + urltest(it, "filter"); + urltest(it, "mask"); + urltest(it, "clip-path"); + linktest(it); + var oldid = $(it.node, "id"); + if (oldid) { + $(it.node, {id: it.id}); + ids.push({ + old: oldid, + id: it.id + }); + } + } + for (i = 0, ii = ids.length; i < ii; i++) { + var fs = uses[ids[i].old]; + if (fs) { + for (var j = 0, jj = fs.length; j < jj; j++) { + fs[j](ids[i].id); + } + } + } + } + /*\ + * Element.clone + [ method ] + ** + * Creates a clone of the element and inserts it after the element + ** + = (Element) the clone + \*/ + elproto.clone = function () { + var clone = wrap(this.node.cloneNode(true)); + if ($(clone.node, "id")) { + $(clone.node, {id: clone.id}); + } + fixids(clone); + clone.insertAfter(this); + return clone; + }; + /*\ + * Element.toDefs + [ method ] + ** + * Moves element to the shared `<defs>` area + ** + = (Element) the element + \*/ + elproto.toDefs = function () { + var defs = getSomeDefs(this); + defs.appendChild(this.node); + return this; + }; + /*\ + * Element.toPattern + [ method ] + ** + * Creates a `<pattern>` element from the current element + ** + * To create a pattern you have to specify the pattern rect: + - x (string|number) + - y (string|number) + - width (string|number) + - height (string|number) + = (Element) the `<pattern>` element + * You can use pattern later on as an argument for `fill` attribute: + | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({ + | fill: "none", + | stroke: "#bada55", + | strokeWidth: 5 + | }).pattern(0, 0, 10, 10), + | c = paper.circle(200, 200, 100); + | c.attr({ + | fill: p + | }); + \*/ + elproto.pattern = elproto.toPattern = function (x, y, width, height) { + var p = make("pattern", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + $(p.node, { + x: x, + y: y, + width: width, + height: height, + patternUnits: "userSpaceOnUse", + id: p.id, + viewBox: [x, y, width, height].join(" ") + }); + p.node.appendChild(this.node); + return p; + }; +// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path. +// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values? + /*\ + * Element.marker + [ method ] + ** + * Creates a `<marker>` element from the current element + ** + * To create a marker you have to specify the bounding rect and reference point: + - x (number) + - y (number) + - width (number) + - height (number) + - refX (number) + - refY (number) + = (Element) the `<marker>` element + * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end. + \*/ + // TODO add usage for markers + elproto.marker = function (x, y, width, height, refX, refY) { + var p = make("marker", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + refX = x.refX || x.cx; + refY = x.refY || x.cy; + x = x.x; + } + $(p.node, { + viewBox: [x, y, width, height].join(" "), + markerWidth: width, + markerHeight: height, + orient: "auto", + refX: refX || 0, + refY: refY || 0, + id: p.id + }); + p.node.appendChild(this.node); + return p; + }; + // animation + function slice(from, to, f) { + return function (arr) { + var res = arr.slice(from, to); + if (res.length == 1) { + res = res[0]; + } + return f ? f(res) : res; + }; + } + var Animation = function (attr, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + this.attr = attr; + this.dur = ms; + easing && (this.easing = easing); + callback && (this.callback = callback); + }; + Snap._.Animation = Animation; + /*\ + * Snap.animation + [ method ] + ** + * Creates an animation object + ** + - attr (object) attributes of final destination + - duration (number) duration of the animation, in milliseconds + - easing (function) #optional one of easing functions of @mina or custom one + - callback (function) #optional callback function that fires when animation ends + = (object) animation object + \*/ + Snap.animation = function (attr, ms, easing, callback) { + return new Animation(attr, ms, easing, callback); + }; + /*\ + * Element.inAnim + [ method ] + ** + * Returns a set of animations that may be able to manipulate the current element + ** + = (object) in format: + o { + o anim (object) animation object, + o mina (object) @mina object, + o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + \*/ + elproto.inAnim = function () { + var el = this, + res = []; + for (var id in el.anims) if (el.anims[has](id)) { + (function (a) { + res.push({ + anim: new Animation(a._attrs, a.dur, a.easing, a._callback), + mina: a, + curStatus: a.status(), + status: function (val) { + return a.status(val); + }, + stop: function () { + a.stop(); + } + }); + }(el.anims[id])); + } + return res; + }; + /*\ + * Snap.animate + [ method ] + ** + * Runs generic animation of one number into another with a caring function + ** + - from (number|array) number or array of numbers + - to (number|array) number or array of numbers + - setter (function) caring function that accepts one number argument + - duration (number) duration, in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function to execute when animation ends + = (object) animation object in @mina format + o { + o id (string) animation id, consider it read-only, + o duration (function) gets or sets the duration of the animation, + o easing (function) easing, + o speed (function) gets or sets the speed of the animation, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + | var rect = Snap().rect(0, 0, 10, 10); + | Snap.animate(0, 10, function (val) { + | rect.attr({ + | x: val + | }); + | }, 1000); + | // in given context is equivalent to + | rect.animate({x: 10}, 1000); + \*/ + Snap.animate = function (from, to, setter, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + var now = mina.time(), + anim = mina(from, to, now, now + ms, mina.time, setter, easing); + callback && eve.once("mina.finish." + anim.id, callback); + return anim; + }; + /*\ + * Element.stop + [ method ] + ** + * Stops all the animations for the current element + ** + = (Element) the current element + \*/ + elproto.stop = function () { + var anims = this.inAnim(); + for (var i = 0, ii = anims.length; i < ii; i++) { + anims[i].stop(); + } + return this; + }; + /*\ + * Element.animate + [ method ] + ** + * Animates the given attributes of the element + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + = (Element) the current element + \*/ + elproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = attrs.dur; + attrs = attrs.attr; + } + var fkeys = [], tkeys = [], keys = {}, from, to, f, eq, + el = this; + for (var key in attrs) if (attrs[has](key)) { + if (el.equal) { + eq = el.equal(key, Str(attrs[key])); + from = eq.from; + to = eq.to; + f = eq.f; + } else { + from = +el.attr(key); + to = +attrs[key]; + } + var len = is(from, "array") ? from.length : 1; + keys[key] = slice(fkeys.length, fkeys.length + len, f); + fkeys = fkeys.concat(from); + tkeys = tkeys.concat(to); + } + var now = mina.time(), + anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) { + var attr = {}; + for (var key in keys) if (keys[has](key)) { + attr[key] = keys[key](val); + } + el.attr(attr); + }, easing); + el.anims[anim.id] = anim; + anim._attrs = attrs; + anim._callback = callback; + eve("snap.animcreated." + el.id, anim); + eve.once("mina.finish." + anim.id, function () { + delete el.anims[anim.id]; + callback && callback.call(el); + }); + eve.once("mina.stop." + anim.id, function () { + delete el.anims[anim.id]; + }); + return el; + }; + var eldata = {}; + /*\ + * Element.data + [ method ] + ** + * Adds or retrieves given value associated with given key. (Don’t confuse + * with `data-` attributes) + * + * See also @Element.removeData + - key (string) key to store data + - value (any) #optional value to store + = (object) @Element + * or, if value is not specified: + = (any) value + > Usage + | for (var i = 0, i < 5, i++) { + | paper.circle(10 + 15 * i, 10, 10) + | .attr({fill: "#000"}) + | .data("i", i) + | .click(function () { + | alert(this.data("i")); + | }); + | } + \*/ + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 0){ + eve("snap.data.get." + this.id, this, data, null); + return data; + } + if (arguments.length == 1) { + if (Snap.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("snap.data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("snap.data.set." + this.id, this, value, key); + return this; + }; + /*\ + * Element.removeData + [ method ] + ** + * Removes value associated with an element by given key. + * If key is not provided, removes all the data of the element. + - key (string) #optional key + = (object) @Element + \*/ + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + /*\ + * Element.outerSVG + [ method ] + ** + * Returns SVG code for the element, equivalent to HTML's `outerHTML`. + * + * See also @Element.innerSVG + = (string) SVG code for the element + \*/ + /*\ + * Element.toString + [ method ] + ** + * See @Element.outerSVG + \*/ + elproto.outerSVG = elproto.toString = toString(1); + /*\ + * Element.innerSVG + [ method ] + ** + * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML` + = (string) SVG code for the element + \*/ + elproto.innerSVG = toString(); + function toString(type) { + return function () { + var res = type ? "<" + this.type : "", + attr = this.node.attributes, + chld = this.node.childNodes; + if (type) { + for (var i = 0, ii = attr.length; i < ii; i++) { + res += " " + attr[i].name + '="' + + attr[i].value.replace(/"/g, '\\"') + '"'; + } + } + if (chld.length) { + type && (res += ">"); + for (i = 0, ii = chld.length; i < ii; i++) { + if (chld[i].nodeType == 3) { + res += chld[i].nodeValue; + } else if (chld[i].nodeType == 1) { + res += wrap(chld[i]).toString(); + } + } + type && (res += "</" + this.type + ">"); + } else { + type && (res += "/>"); + } + return res; + }; + } + elproto.toDataURL = function () { + if (window && window.btoa) { + var bb = this.getBBox(), + svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', { + x: +bb.x.toFixed(3), + y: +bb.y.toFixed(3), + width: +bb.width.toFixed(3), + height: +bb.height.toFixed(3), + contents: this.outerSVG() + }); + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg))); + } + }; + /*\ + * Fragment.select + [ method ] + ** + * See @Element.select + \*/ + Fragment.prototype.select = elproto.select; + /*\ + * Fragment.selectAll + [ method ] + ** + * See @Element.selectAll + \*/ + Fragment.prototype.selectAll = elproto.selectAll; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var objectToString = Object.prototype.toString, + Str = String, + math = Math, + E = ""; + function Matrix(a, b, c, d, e, f) { + if (b == null && objectToString.call(a) == "[object SVGMatrix]") { + this.a = a.a; + this.b = a.b; + this.c = a.c; + this.d = a.d; + this.e = a.e; + this.f = a.f; + return; + } + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + /*\ + * Matrix.add + [ method ] + ** + * Adds the given matrix to existing one + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - matrix (object) @Matrix + \*/ + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + return this; + }; + /*\ + * Matrix.invert + [ method ] + ** + * Returns an inverted version of the matrix + = (object) @Matrix + \*/ + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + /*\ + * Matrix.clone + [ method ] + ** + * Returns a copy of the matrix + = (object) @Matrix + \*/ + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + /*\ + * Matrix.translate + [ method ] + ** + * Translate the matrix + - x (number) horizontal offset distance + - y (number) vertical offset distance + \*/ + matrixproto.translate = function (x, y) { + return this.add(1, 0, 0, 1, x, y); + }; + /*\ + * Matrix.scale + [ method ] + ** + * Scales the matrix + - x (number) amount to be scaled, with `1` resulting in no change + - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.) + - cx (number) #optional horizontal origin point from which to scale + - cy (number) #optional vertical origin point from which to scale + * Default cx, cy is the middle point of the element. + \*/ + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + return this; + }; + /*\ + * Matrix.rotate + [ method ] + ** + * Rotates the matrix + - a (number) angle of rotation, in degrees + - x (number) horizontal origin point from which to rotate + - y (number) vertical origin point from which to rotate + \*/ + matrixproto.rotate = function (a, x, y) { + a = Snap.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + return this.add(1, 0, 0, 1, -x, -y); + }; + /*\ + * Matrix.x + [ method ] + ** + * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y + - x (number) + - y (number) + = (number) x + \*/ + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + /*\ + * Matrix.y + [ method ] + ** + * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x + - x (number) + - y (number) + = (number) y + \*/ + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + /*\ + * Matrix.determinant + [ method ] + ** + * Finds determinant of the given matrix. + = (number) determinant + \*/ + matrixproto.determinant = function () { + return this.a * this.d - this.b * this.c; + }; + /*\ + * Matrix.split + [ method ] + ** + * Splits matrix into primitive transformations + = (object) in format: + o dx (number) translation by x + o dy (number) translation by y + o scalex (number) scale by x + o scaley (number) scale by y + o shear (number) shear + o rotate (number) rotation in deg + o isSimple (boolean) could it be represented via simple transformations + \*/ + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + if (this.determinant() < 0) { + out.scalex = -out.scalex; + } + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = Snap.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = Snap.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + /*\ + * Matrix.toTransformString + [ method ] + ** + * Returns transform string that represents given matrix + = (string) transform string + \*/ + matrixproto.toTransformString = function (shorter) { + var s = shorter || this.split(); + if (!+s.shear.toFixed(9)) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + /*\ + * Snap.Matrix + [ method ] + ** + * Matrix constructor, extend on your own risk. + * To create matrices use @Snap.matrix. + \*/ + Snap.Matrix = Matrix; + /*\ + * Snap.matrix + [ method ] + ** + * Utility method + ** + * Returns a matrix based on the given parameters + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - svgMatrix (SVGMatrix) + = (object) @Matrix + \*/ + Snap.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var has = "hasOwnProperty", + make = Snap._.make, + wrap = Snap._.wrap, + is = Snap.is, + getSomeDefs = Snap._.getSomeDefs, + reURLValue = /^url\(#?([^)]+)\)$/, + $ = Snap._.$, + URL = Snap.url, + Str = String, + separator = Snap._.separator, + E = ""; + // Attributes event handlers + eve.on("snap.util.attr.mask", function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value.type == "mask") { + var mask = value; + } else { + mask = make("mask", getSomeDefs(this)); + mask.node.appendChild(value.node); + } + !mask.node.id && $(mask.node, { + id: mask.id + }); + $(this.node, { + mask: URL(mask.id) + }); + } + }); + (function (clipIt) { + eve.on("snap.util.attr.clip", clipIt); + eve.on("snap.util.attr.clip-path", clipIt); + eve.on("snap.util.attr.clipPath", clipIt); + }(function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value.type == "clipPath") { + var clip = value; + } else { + clip = make("clipPath", getSomeDefs(this)); + clip.node.appendChild(value.node); + !clip.node.id && $(clip.node, { + id: clip.id + }); + } + $(this.node, { + "clip-path": URL(clip.node.id || clip.id) + }); + } + })); + function fillStroke(name) { + return function (value) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1 && + (value.node.firstChild.tagName == "radialGradient" || + value.node.firstChild.tagName == "linearGradient" || + value.node.firstChild.tagName == "pattern")) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value instanceof Element) { + if (value.type == "radialGradient" || value.type == "linearGradient" + || value.type == "pattern") { + if (!value.node.id) { + $(value.node, { + id: value.id + }); + } + var fill = URL(value.node.id); + } else { + fill = value.attr(name); + } + } else { + fill = Snap.color(value); + if (fill.error) { + var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value); + if (grad) { + if (!grad.node.id) { + $(grad.node, { + id: grad.id + }); + } + fill = URL(grad.node.id); + } else { + fill = value; + } + } else { + fill = Str(fill); + } + } + var attrs = {}; + attrs[name] = fill; + $(this.node, attrs); + this.node.style[name] = E; + }; + } + eve.on("snap.util.attr.fill", fillStroke("fill")); + eve.on("snap.util.attr.stroke", fillStroke("stroke")); + var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i; + eve.on("snap.util.grad.parse", function parseGrad(string) { + string = Str(string); + var tokens = string.match(gradrg); + if (!tokens) { + return null; + } + var type = tokens[1], + params = tokens[2], + stops = tokens[3]; + params = params.split(/\s*,\s*/).map(function (el) { + return +el == el ? +el : el; + }); + if (params.length == 1 && params[0] == 0) { + params = []; + } + stops = stops.split("-"); + stops = stops.map(function (el) { + el = el.split(":"); + var out = { + color: el[0] + }; + if (el[1]) { + out.offset = parseFloat(el[1]); + } + return out; + }); + return { + type: type, + params: params, + stops: stops + }; + }); + + eve.on("snap.util.attr.d", function (value) { + eve.stop(); + if (is(value, "array") && is(value[0], "array")) { + value = Snap.path.toString.call(value); + } + value = Str(value); + if (value.match(/[ruo]/i)) { + value = Snap.path.toAbsolute(value); + } + $(this.node, {d: value}); + })(-1); + eve.on("snap.util.attr.#text", function (value) { + eve.stop(); + value = Str(value); + var txt = glob.doc.createTextNode(value); + while (this.node.firstChild) { + this.node.removeChild(this.node.firstChild); + } + this.node.appendChild(txt); + })(-1); + eve.on("snap.util.attr.path", function (value) { + eve.stop(); + this.attr({d: value}); + })(-1); + eve.on("snap.util.attr.class", function (value) { + eve.stop(); + this.node.className.baseVal = value; + })(-1); + eve.on("snap.util.attr.viewBox", function (value) { + var vb; + if (is(value, "object") && "x" in value) { + vb = [value.x, value.y, value.width, value.height].join(" "); + } else if (is(value, "array")) { + vb = value.join(" "); + } else { + vb = value; + } + $(this.node, { + viewBox: vb + }); + eve.stop(); + })(-1); + eve.on("snap.util.attr.transform", function (value) { + this.transform(value); + eve.stop(); + })(-1); + eve.on("snap.util.attr.r", function (value) { + if (this.type == "rect") { + eve.stop(); + $(this.node, { + rx: value, + ry: value + }); + } + })(-1); + eve.on("snap.util.attr.textpath", function (value) { + eve.stop(); + if (this.type == "text") { + var id, tp, node; + if (!value && this.textPath) { + tp = this.textPath; + while (tp.node.firstChild) { + this.node.appendChild(tp.node.firstChild); + } + tp.remove(); + delete this.textPath; + return; + } + if (is(value, "string")) { + var defs = getSomeDefs(this), + path = wrap(defs.parentNode).path(value); + defs.appendChild(path.node); + id = path.id; + path.attr({id: id}); + } else { + value = wrap(value); + if (value instanceof Element) { + id = value.attr("id"); + if (!id) { + id = value.id; + value.attr({id: id}); + } + } + } + if (id) { + tp = this.textPath; + node = this.node; + if (tp) { + tp.attr({"xlink:href": "#" + id}); + } else { + tp = $("textPath", { + "xlink:href": "#" + id + }); + while (node.firstChild) { + tp.appendChild(node.firstChild); + } + node.appendChild(tp); + this.textPath = wrap(tp); + } + } + } + })(-1); + eve.on("snap.util.attr.text", function (value) { + if (this.type == "text") { + var i = 0, + node = this.node, + tuner = function (chunk) { + var out = $("tspan"); + if (is(chunk, "array")) { + for (var i = 0; i < chunk.length; i++) { + out.appendChild(tuner(chunk[i])); + } + } else { + out.appendChild(glob.doc.createTextNode(chunk)); + } + out.normalize && out.normalize(); + return out; + }; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var tuned = tuner(value); + while (tuned.firstChild) { + node.appendChild(tuned.firstChild); + } + } + eve.stop(); + })(-1); + function setFontSize(value) { + eve.stop(); + if (value == +value) { + value += "px"; + } + this.node.style.fontSize = value; + } + eve.on("snap.util.attr.fontSize", setFontSize)(-1); + eve.on("snap.util.attr.font-size", setFontSize)(-1); + + + eve.on("snap.util.getattr.transform", function () { + eve.stop(); + return this.transform(); + })(-1); + eve.on("snap.util.getattr.textpath", function () { + eve.stop(); + return this.textPath; + })(-1); + // Markers + (function () { + function getter(end) { + return function () { + eve.stop(); + var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end); + if (style == "none") { + return style; + } else { + return Snap(glob.doc.getElementById(style.match(reURLValue)[1])); + } + }; + } + function setter(end) { + return function (value) { + eve.stop(); + var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1); + if (value == "" || !value) { + this.node.style[name] = "none"; + return; + } + if (value.type == "marker") { + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + } + this.node.style[name] = URL(id); + return; + } + }; + } + eve.on("snap.util.getattr.marker-end", getter("end"))(-1); + eve.on("snap.util.getattr.markerEnd", getter("end"))(-1); + eve.on("snap.util.getattr.marker-start", getter("start"))(-1); + eve.on("snap.util.getattr.markerStart", getter("start"))(-1); + eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1); + eve.on("snap.util.getattr.markerMid", getter("mid"))(-1); + eve.on("snap.util.attr.marker-end", setter("end"))(-1); + eve.on("snap.util.attr.markerEnd", setter("end"))(-1); + eve.on("snap.util.attr.marker-start", setter("start"))(-1); + eve.on("snap.util.attr.markerStart", setter("start"))(-1); + eve.on("snap.util.attr.marker-mid", setter("mid"))(-1); + eve.on("snap.util.attr.markerMid", setter("mid"))(-1); + }()); + eve.on("snap.util.getattr.r", function () { + if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) { + eve.stop(); + return $(this.node, "rx"); + } + })(-1); + function textExtract(node) { + var out = []; + var children = node.childNodes; + for (var i = 0, ii = children.length; i < ii; i++) { + var chi = children[i]; + if (chi.nodeType == 3) { + out.push(chi.nodeValue); + } + if (chi.tagName == "tspan") { + if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) { + out.push(chi.firstChild.nodeValue); + } else { + out.push(textExtract(chi)); + } + } + } + return out; + } + eve.on("snap.util.getattr.text", function () { + if (this.type == "text" || this.type == "tspan") { + eve.stop(); + var out = textExtract(this.node); + return out.length == 1 ? out[0] : out; + } + })(-1); + eve.on("snap.util.getattr.#text", function () { + return this.node.textContent; + })(-1); + eve.on("snap.util.getattr.viewBox", function () { + eve.stop(); + var vb = $(this.node, "viewBox"); + if (vb) { + vb = vb.split(separator); + return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.points", function () { + var p = $(this.node, "points"); + eve.stop(); + if (p) { + return p.split(separator); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.path", function () { + var p = $(this.node, "d"); + eve.stop(); + return p; + })(-1); + eve.on("snap.util.getattr.class", function () { + return this.node.className.baseVal; + })(-1); + function getFontSize() { + eve.stop(); + return this.node.style.fontSize; + } + eve.on("snap.util.getattr.fontSize", getFontSize)(-1); + eve.on("snap.util.getattr.font-size", getFontSize)(-1); +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var rgNotSpace = /\S+/g, + rgBadSpace = /[\t\r\n\f]/g, + rgTrim = /(^\s+|\s+$)/g, + Str = String, + elproto = Element.prototype; + /*\ + * Element.addClass + [ method ] + ** + * Adds given class name or list of class names to the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.addClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + + if (classes.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (!~pos) { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.removeClass + [ method ] + ** + * Removes given class name or list of class names from the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.removeClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + if (curClasses.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.hasClass + [ method ] + ** + * Checks if the element has a given class name in the list of class names applied to it. + - value (string) class name + ** + = (boolean) `true` if the element has given class + \*/ + elproto.hasClass = function (value) { + var elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || []; + return !!~curClasses.indexOf(value); + }; + /*\ + * Element.toggleClass + [ method ] + ** + * Add or remove one or more classes from the element, depending on either + * the class’s presence or the value of the `flag` argument. + - value (string) class name or space separated list of class names + - flag (boolean) value to determine whether the class should be added or removed + ** + = (Element) original element. + \*/ + elproto.toggleClass = function (value, flag) { + if (flag != null) { + if (flag) { + return this.addClass(value); + } else { + return this.removeClass(value); + } + } + var classes = (value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } else { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var operators = { + "+": function (x, y) { + return x + y; + }, + "-": function (x, y) { + return x - y; + }, + "/": function (x, y) { + return x / y; + }, + "*": function (x, y) { + return x * y; + } + }, + Str = String, + reUnit = /[a-z]+$/i, + reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/; + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + eve.on("snap.util.attr", function (val) { + var plus = Str(val).match(reAddon); + if (plus) { + var evnt = eve.nt(), + name = evnt.substring(evnt.lastIndexOf(".") + 1), + a = this.attr(name), + atr = {}; + eve.stop(); + var unit = plus[3] || "", + aUnit = a.match(reUnit), + op = operators[plus[1]]; + if (aUnit && aUnit == unit) { + val = op(parseFloat(a), +plus[2]); + } else { + a = this.asPX(name); + val = op(this.asPX(name), this.asPX(name, plus[2] + unit)); + } + if (isNaN(a) || isNaN(val)) { + return; + } + atr[name] = val; + this.attr(atr); + } + })(-10); + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this, + bplus = Str(b).match(reAddon); + if (bplus) { + eve.stop(); + var unit = bplus[3] || "", + aUnit = a.match(reUnit), + op = operators[bplus[1]]; + if (aUnit && aUnit == unit) { + return { + from: parseFloat(a), + to: op(parseFloat(a), +bplus[2]), + f: getUnit(aUnit) + }; + } else { + a = this.asPX(name); + return { + from: a, + to: op(a, this.asPX(name, bplus[2] + unit)), + f: getNumber + }; + } + } + })(-10); +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var proto = Paper.prototype, + is = Snap.is; + /*\ + * Paper.rect + [ method ] + * + * Draws a rectangle + ** + - x (number) x coordinate of the top left corner + - y (number) y coordinate of the top left corner + - width (number) width + - height (number) height + - rx (number) #optional horizontal radius for rounded corners, default is 0 + - ry (number) #optional vertical radius for rounded corners, default is rx or 0 + = (object) the `rect` element + ** + > Usage + | // regular rectangle + | var c = paper.rect(10, 10, 50, 50); + | // rectangle with rounded corners + | var c = paper.rect(40, 40, 50, 50, 10); + \*/ + proto.rect = function (x, y, w, h, rx, ry) { + var attr; + if (ry == null) { + ry = rx; + } + if (is(x, "object") && x == "[object Object]") { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + width: w, + height: h + }; + if (rx != null) { + attr.rx = rx; + attr.ry = ry; + } + } + return this.el("rect", attr); + }; + /*\ + * Paper.circle + [ method ] + ** + * Draws a circle + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - r (number) radius + = (object) the `circle` element + ** + > Usage + | var c = paper.circle(50, 50, 40); + \*/ + proto.circle = function (cx, cy, r) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr = { + cx: cx, + cy: cy, + r: r + }; + } + return this.el("circle", attr); + }; + + var preload = (function () { + function onerror() { + this.parentNode.removeChild(this); + } + return function (src, f) { + var img = glob.doc.createElement("img"), + body = glob.doc.body; + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(img); + img.onload = img.onerror = null; + body.removeChild(img); + }; + img.onerror = onerror; + body.appendChild(img); + img.src = src; + }; + }()); + + /*\ + * Paper.image + [ method ] + ** + * Places an image on the surface + ** + - src (string) URI of the source image + - x (number) x offset position + - y (number) y offset position + - width (number) width of the image + - height (number) height of the image + = (object) the `image` element + * or + = (object) Snap element object with type `image` + ** + > Usage + | var c = paper.image("apple.png", 10, 10, 80, 80); + \*/ + proto.image = function (src, x, y, width, height) { + var el = this.el("image"); + if (is(src, "object") && "src" in src) { + el.attr(src); + } else if (src != null) { + var set = { + "xlink:href": src, + preserveAspectRatio: "none" + }; + if (x != null && y != null) { + set.x = x; + set.y = y; + } + if (width != null && height != null) { + set.width = width; + set.height = height; + } else { + preload(src, function () { + Snap._.$(el.node, { + width: this.offsetWidth, + height: this.offsetHeight + }); + }); + } + Snap._.$(el.node, set); + } + return el; + }; + /*\ + * Paper.ellipse + [ method ] + ** + * Draws an ellipse + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - rx (number) horizontal radius + - ry (number) vertical radius + = (object) the `ellipse` element + ** + > Usage + | var c = paper.ellipse(50, 50, 40, 20); + \*/ + proto.ellipse = function (cx, cy, rx, ry) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr ={ + cx: cx, + cy: cy, + rx: rx, + ry: ry + }; + } + return this.el("ellipse", attr); + }; + // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier. + /*\ + * Paper.path + [ method ] + ** + * Creates a `<path>` element using the given string as the path's definition + - pathString (string) #optional path string in SVG format + * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example: + | "M10,20L30,40" + * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates. + * + # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p> + # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> + # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> + # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> + # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> + # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> + # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> + # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> + # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> + # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> + # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> + # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> + # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> + * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier. + * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point. + > Usage + | var c = paper.path("M10 10L90 90"); + | // draw a diagonal line: + | // move to 10,10, line to 90,90 + \*/ + proto.path = function (d) { + var attr; + if (is(d, "object") && !is(d, "array")) { + attr = d; + } else if (d) { + attr = {d: d}; + } + return this.el("path", attr); + }; + /*\ + * Paper.g + [ method ] + ** + * Creates a group element + ** + - varargs (…) #optional elements to nest within the group + = (object) the `g` element + ** + > Usage + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(c2, c1); // note that the order of elements is different + * or + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(); + | g.add(c2, c1); + \*/ + /*\ + * Paper.group + [ method ] + ** + * See @Paper.g + \*/ + proto.group = proto.g = function (first) { + var attr, + el = this.el("g"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.svg + [ method ] + ** + * Creates a nested SVG element. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `svg` element + ** + \*/ + proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) { + var attrs = {}; + if (is(x, "object") && y == null) { + attrs = x; + } else { + if (x != null) { + attrs.x = x; + } + if (y != null) { + attrs.y = y; + } + if (width != null) { + attrs.width = width; + } + if (height != null) { + attrs.height = height; + } + if (vbx != null && vby != null && vbw != null && vbh != null) { + attrs.viewBox = [vbx, vby, vbw, vbh]; + } + } + return this.el("svg", attrs); + }; + /*\ + * Paper.mask + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a mask. + ** + = (object) the `mask` element + ** + \*/ + proto.mask = function (first) { + var attr, + el = this.el("mask"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.ptrn + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a pattern. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `pattern` element + ** + \*/ + proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) { + if (is(x, "object")) { + var attr = x; + } else { + attr = {patternUnits: "userSpaceOnUse"}; + if (x) { + attr.x = x; + } + if (y) { + attr.y = y; + } + if (width != null) { + attr.width = width; + } + if (height != null) { + attr.height = height; + } + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } else { + attr.viewBox = [x || 0, y || 0, width || 0, height || 0]; + } + } + return this.el("pattern", attr); + }; + /*\ + * Paper.use + [ method ] + ** + * Creates a <use> element. + - id (string) @optional id of element to link + * or + - id (Element) @optional element to link + ** + = (object) the `use` element + ** + \*/ + proto.use = function (id) { + if (id != null) { + if (id instanceof Element) { + if (!id.attr("id")) { + id.attr({id: Snap._.id(id)}); + } + id = id.attr("id"); + } + if (String(id).charAt() == "#") { + id = id.substring(1); + } + return this.el("use", {"xlink:href": "#" + id}); + } else { + return Element.prototype.use.call(this); + } + }; + /*\ + * Paper.symbol + [ method ] + ** + * Creates a <symbol> element. + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + = (object) the `symbol` element + ** + \*/ + proto.symbol = function (vx, vy, vw, vh) { + var attr = {}; + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } + + return this.el("symbol", attr); + }; + /*\ + * Paper.text + [ method ] + ** + * Draws a text string + ** + - x (number) x coordinate position + - y (number) y coordinate position + - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements + = (object) the `text` element + ** + > Usage + | var t1 = paper.text(50, 50, "Snap"); + | var t2 = paper.text(50, 50, ["S","n","a","p"]); + | // Text path usage + | t1.attr({textpath: "M10,10L100,100"}); + | // or + | var pth = paper.path("M10,10L100,100"); + | t1.attr({textpath: pth}); + \*/ + proto.text = function (x, y, text) { + var attr = {}; + if (is(x, "object")) { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + text: text || "" + }; + } + return this.el("text", attr); + }; + /*\ + * Paper.line + [ method ] + ** + * Draws a line + ** + - x1 (number) x coordinate position of the start + - y1 (number) y coordinate position of the start + - x2 (number) x coordinate position of the end + - y2 (number) y coordinate position of the end + = (object) the `line` element + ** + > Usage + | var t1 = paper.line(50, 50, 100, 100); + \*/ + proto.line = function (x1, y1, x2, y2) { + var attr = {}; + if (is(x1, "object")) { + attr = x1; + } else if (x1 != null) { + attr = { + x1: x1, + x2: x2, + y1: y1, + y2: y2 + }; + } + return this.el("line", attr); + }; + /*\ + * Paper.polyline + [ method ] + ** + * Draws a polyline + ** + - points (array) array of points + * or + - varargs (…) points + = (object) the `polyline` element + ** + > Usage + | var p1 = paper.polyline([10, 10, 100, 100]); + | var p2 = paper.polyline(10, 10, 100, 100); + \*/ + proto.polyline = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polyline", attr); + }; + /*\ + * Paper.polygon + [ method ] + ** + * Draws a polygon. See @Paper.polyline + \*/ + proto.polygon = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polygon", attr); + }; + // gradients + (function () { + var $ = Snap._.$; + // gradients' helpers + function Gstops() { + return this.selectAll("stop"); + } + function GaddStop(color, offset) { + var stop = $("stop"), + attr = { + offset: +offset + "%" + }; + color = Snap.color(color); + attr["stop-color"] = color.hex; + if (color.opacity < 1) { + attr["stop-opacity"] = color.opacity; + } + $(stop, attr); + this.node.appendChild(stop); + return this; + } + function GgetBBox() { + if (this.type == "linearGradient") { + var x1 = $(this.node, "x1") || 0, + x2 = $(this.node, "x2") || 1, + y1 = $(this.node, "y1") || 0, + y2 = $(this.node, "y2") || 0; + return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1)); + } else { + var cx = this.node.cx || .5, + cy = this.node.cy || .5, + r = this.node.r || 0; + return Snap._.box(cx - r, cy - r, r * 2, r * 2); + } + } + function gradient(defs, str) { + var grad = eve("snap.util.grad.parse", null, str).firstDefined(), + el; + if (!grad) { + return null; + } + grad.params.unshift(defs); + if (grad.type.toLowerCase() == "l") { + el = gradientLinear.apply(0, grad.params); + } else { + el = gradientRadial.apply(0, grad.params); + } + if (grad.type != grad.type.toLowerCase()) { + $(el.node, { + gradientUnits: "userSpaceOnUse" + }); + } + var stops = grad.stops, + len = stops.length, + start = 0, + j = 0; + function seed(i, end) { + var step = (end - start) / (i - j); + for (var k = j; k < i; k++) { + stops[k].offset = +(+start + step * (k - j)).toFixed(2); + } + j = i; + start = end; + } + len--; + for (var i = 0; i < len; i++) if ("offset" in stops[i]) { + seed(i, stops[i].offset); + } + stops[len].offset = stops[len].offset || 100; + seed(len, stops[len].offset); + for (i = 0; i <= len; i++) { + var stop = stops[i]; + el.addStop(stop.color, stop.offset); + } + return el; + } + function gradientLinear(defs, x1, y1, x2, y2) { + var el = Snap._.make("linearGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (x1 != null) { + $(el.node, { + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }); + } + return el; + } + function gradientRadial(defs, cx, cy, r, fx, fy) { + var el = Snap._.make("radialGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (cx != null) { + $(el.node, { + cx: cx, + cy: cy, + r: r + }); + } + if (fx != null && fy != null) { + $(el.node, { + fx: fx, + fy: fy + }); + } + return el; + } + /*\ + * Paper.gradient + [ method ] + ** + * Creates a gradient element + ** + - gradient (string) gradient descriptor + > Gradient Descriptor + * The gradient descriptor is an expression formatted as + * follows: `<type>(<coords>)<colors>`. The `<type>` can be + * either linear or radial. The uppercase `L` or `R` letters + * indicate absolute coordinates offset from the SVG surface. + * Lowercase `l` or `r` letters indicate coordinates + * calculated relative to the element to which the gradient is + * applied. Coordinates specify a linear gradient vector as + * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`, + * `r` and optional `fx`, `fy` specifying a focal point away + * from the center of the circle. Specify `<colors>` as a list + * of dash-separated CSS color values. Each color may be + * followed by a custom offset value, separated with a colon + * character. + > Examples + * Linear gradient, relative from top-left corner to bottom-right + * corner, from black through red to white: + | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff"); + * Linear gradient, absolute from (0, 0) to (100, 100), from black + * through red at 25% to white: + | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff"); + * Radial gradient, relative from the center of the element with radius + * half the width, from black to white: + | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff"); + * To apply the gradient: + | paper.circle(50, 50, 40).attr({ + | fill: g + | }); + = (object) the `gradient` element + \*/ + proto.gradient = function (str) { + return gradient(this.defs, str); + }; + proto.gradientLinear = function (x1, y1, x2, y2) { + return gradientLinear(this.defs, x1, y1, x2, y2); + }; + proto.gradientRadial = function (cx, cy, r, fx, fy) { + return gradientRadial(this.defs, cx, cy, r, fx, fy); + }; + /*\ + * Paper.toString + [ method ] + ** + * Returns SVG code for the @Paper + = (string) SVG code for the @Paper + \*/ + proto.toString = function () { + var doc = this.node.ownerDocument, + f = doc.createDocumentFragment(), + d = doc.createElement("div"), + svg = this.node.cloneNode(true), + res; + f.appendChild(d); + d.appendChild(svg); + Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"}); + res = d.innerHTML; + f.removeChild(f.firstChild); + return res; + }; + /*\ + * Paper.toDataURL + [ method ] + ** + * Returns SVG code for the @Paper as Data URI string. + = (string) Data URI string + \*/ + proto.toDataURL = function () { + if (window && window.btoa) { + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this))); + } + }; + /*\ + * Paper.clear + [ method ] + ** + * Removes all child nodes of the paper, except <defs>. + \*/ + proto.clear = function () { + var node = this.node.firstChild, + next; + while (node) { + next = node.nextSibling; + if (node.tagName != "defs") { + node.parentNode.removeChild(node); + } else { + proto.clear.call({node: node}); + } + node = next; + } + }; + }()); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + is = Snap.is, + clone = Snap._.clone, + has = "hasOwnProperty", + p2s = /,?([a-z]),?/gi, + toFloat = parseFloat, + math = Math, + PI = math.PI, + mmin = math.min, + mmax = math.max, + pow = math.pow, + abs = math.abs; + function paths(ps) { + var p = paths.ps = paths.ps || {}; + if (p[ps]) { + p[ps].sleep = 100; + } else { + p[ps] = { + sleep: 100 + }; + } + setTimeout(function () { + for (var key in p) if (p[has](key) && key != ps) { + p[key].sleep--; + !p[key].sleep && delete p[key]; + } + }); + return p[ps]; + } + function box(x, y, width, height) { + if (x == null) { + x = y = width = height = 0; + } + if (y == null) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + return { + x: x, + y: y, + width: width, + w: width, + height: height, + h: height, + x2: x + width, + y2: y + height, + cx: x + width / 2, + cy: y + height / 2, + r1: math.min(width, height) / 2, + r2: math.max(width, height) / 2, + r0: math.sqrt(width * width + height * height) / 2, + path: rectPath(x, y, width, height), + vb: [x, y, width, height].join(" ") + }; + } + function toString() { + return this.join(",").replace(p2s, "$1"); + } + function pathClone(pathArray) { + var res = clone(pathArray); + res.toString = toString; + return res; + } + function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + if (length == null) { + return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + } else { + return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, + getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); + } + } + function getLengthFactory(istotal, subpath) { + function O(val) { + return +(+val).toFixed(3); + } + return Snap._.cacher(function (path, length, onlystart) { + if (path instanceof Element) { + path = path.attr("d"); + } + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += [ + "C" + O(point.start.x), + O(point.start.y), + O(point.m.x), + O(point.m.y), + O(point.x), + O(point.y) + ]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = [ + "M" + O(point.x), + O(point.y) + "C" + O(point.n.x), + O(point.n.y), + O(point.end.x), + O(point.end.y), + O(p[5]), + O(p[6]) + ].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return point; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + return point; + }, null, Snap._.clone); + } + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + // (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + } + function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + if (!Snap.is(p1x, "array")) { + p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; + } + var bbox = curveDim.apply(null, p1x); + return box( + bbox.min.x, + bbox.min.y, + bbox.max.x - bbox.min.x, + bbox.max.y - bbox.min.y + ); + } + function isPointInsideBBox(bbox, x, y) { + return x >= bbox.x && + x <= bbox.x + bbox.width && + y >= bbox.y && + y <= bbox.y + bbox.height; + } + function isBBoxIntersect(bbox1, bbox2) { + bbox1 = box(bbox1); + bbox2 = box(bbox2); + return isPointInsideBBox(bbox2, bbox1.x, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2) + || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x + || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) + && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y + || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); + } + function base3(t, p1, p2, p3, p4) { + var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, + t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; + return t * t2 - 3 * p1 + 3 * p2; + } + function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { + if (z == null) { + z = 1; + } + z = z > 1 ? 1 : z < 0 ? 0 : z; + var z2 = z / 2, + n = 12, + Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816], + Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], + sum = 0; + for (var i = 0; i < n; i++) { + var ct = z2 * Tvalues[i] + z2, + xbase = base3(ct, x1, x2, x3, x4), + ybase = base3(ct, y1, y2, y3, y4), + comb = xbase * xbase + ybase * ybase; + sum += Cvalues[i] * math.sqrt(comb); + } + return z2 * sum; + } + function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { + if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { + return; + } + var t = 1, + step = t / 2, + t2 = t - step, + l, + e = .01; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + while (abs(l - ll) > e) { + step /= 2; + t2 += (l < ll ? 1 : -1) * step; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + } + return t2; + } + function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { + if ( + mmax(x1, x2) < mmin(x3, x4) || + mmin(x1, x2) > mmax(x3, x4) || + mmax(y1, y2) < mmin(y3, y4) || + mmin(y1, y2) > mmax(y3, y4) + ) { + return; + } + var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), + ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), + denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + + if (!denominator) { + return; + } + var px = nx / denominator, + py = ny / denominator, + px2 = +px.toFixed(2), + py2 = +py.toFixed(2); + if ( + px2 < +mmin(x1, x2).toFixed(2) || + px2 > +mmax(x1, x2).toFixed(2) || + px2 < +mmin(x3, x4).toFixed(2) || + px2 > +mmax(x3, x4).toFixed(2) || + py2 < +mmin(y1, y2).toFixed(2) || + py2 > +mmax(y1, y2).toFixed(2) || + py2 < +mmin(y3, y4).toFixed(2) || + py2 > +mmax(y3, y4).toFixed(2) + ) { + return; + } + return {x: px, y: py}; + } + function inter(bez1, bez2) { + return interHelper(bez1, bez2); + } + function interCount(bez1, bez2) { + return interHelper(bez1, bez2, 1); + } + function interHelper(bez1, bez2, justCount) { + var bbox1 = bezierBBox(bez1), + bbox2 = bezierBBox(bez2); + if (!isBBoxIntersect(bbox1, bbox2)) { + return justCount ? 0 : []; + } + var l1 = bezlen.apply(0, bez1), + l2 = bezlen.apply(0, bez2), + n1 = ~~(l1 / 8), + n2 = ~~(l2 / 8), + dots1 = [], + dots2 = [], + xy = {}, + res = justCount ? 0 : []; + for (var i = 0; i < n1 + 1; i++) { + var p = findDotsAtSegment.apply(0, bez1.concat(i / n1)); + dots1.push({x: p.x, y: p.y, t: i / n1}); + } + for (i = 0; i < n2 + 1; i++) { + p = findDotsAtSegment.apply(0, bez2.concat(i / n2)); + dots2.push({x: p.x, y: p.y, t: i / n2}); + } + for (i = 0; i < n1; i++) { + for (var j = 0; j < n2; j++) { + var di = dots1[i], + di1 = dots1[i + 1], + dj = dots2[j], + dj1 = dots2[j + 1], + ci = abs(di1.x - di.x) < .001 ? "y" : "x", + cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", + is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); + if (is) { + if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { + continue; + } + xy[is.x.toFixed(4)] = is.y.toFixed(4); + var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), + t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); + if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) { + if (justCount) { + res++; + } else { + res.push({ + x: is.x, + y: is.y, + t1: t1, + t2: t2 + }); + } + } + } + } + } + return res; + } + function pathIntersection(path1, path2) { + return interPathHelper(path1, path2); + } + function pathIntersectionNumber(path1, path2) { + return interPathHelper(path1, path2, 1); + } + function interPathHelper(path1, path2, justCount) { + path1 = path2curve(path1); + path2 = path2curve(path2); + var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, + res = justCount ? 0 : []; + for (var i = 0, ii = path1.length; i < ii; i++) { + var pi = path1[i]; + if (pi[0] == "M") { + x1 = x1m = pi[1]; + y1 = y1m = pi[2]; + } else { + if (pi[0] == "C") { + bez1 = [x1, y1].concat(pi.slice(1)); + x1 = bez1[6]; + y1 = bez1[7]; + } else { + bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; + x1 = x1m; + y1 = y1m; + } + for (var j = 0, jj = path2.length; j < jj; j++) { + var pj = path2[j]; + if (pj[0] == "M") { + x2 = x2m = pj[1]; + y2 = y2m = pj[2]; + } else { + if (pj[0] == "C") { + bez2 = [x2, y2].concat(pj.slice(1)); + x2 = bez2[6]; + y2 = bez2[7]; + } else { + bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; + x2 = x2m; + y2 = y2m; + } + var intr = interHelper(bez1, bez2, justCount); + if (justCount) { + res += intr; + } else { + for (var k = 0, kk = intr.length; k < kk; k++) { + intr[k].segment1 = i; + intr[k].segment2 = j; + intr[k].bez1 = bez1; + intr[k].bez2 = bez2; + } + res = res.concat(intr); + } + } + } + } + } + return res; + } + function isPointInsidePath(path, x, y) { + var bbox = pathBBox(path); + return isPointInsideBBox(bbox, x, y) && + interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; + } + function pathBBox(path) { + var pth = paths(path); + if (pth.bbox) { + return clone(pth.bbox); + } + if (!path) { + return box(); + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X.concat(dim.min.x, dim.max.x); + Y = Y.concat(dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin.apply(0, X), + ymin = mmin.apply(0, Y), + xmax = mmax.apply(0, X), + ymax = mmax.apply(0, Y), + bb = box(xmin, ymin, xmax - xmin, ymax - ymin); + pth.bbox = clone(bb); + return bb; + } + function rectPath(x, y, w, h, r) { + if (r) { + return [ + ["M", +x + (+r), y], + ["l", w - r * 2, 0], + ["a", r, r, 0, 0, 1, r, r], + ["l", 0, h - r * 2], + ["a", r, r, 0, 0, 1, -r, r], + ["l", r * 2 - w, 0], + ["a", r, r, 0, 0, 1, -r, -r], + ["l", 0, r * 2 - h], + ["a", r, r, 0, 0, 1, r, -r], + ["z"] + ]; + } + var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + res.toString = toString; + return res; + } + function ellipsePath(x, y, rx, ry, a) { + if (a == null && ry == null) { + ry = rx; + } + x = +x; + y = +y; + rx = +rx; + ry = +ry; + if (a != null) { + var rad = Math.PI / 180, + x1 = x + rx * Math.cos(-ry * rad), + x2 = x + rx * Math.cos(-a * rad), + y1 = y + rx * Math.sin(-ry * rad), + y2 = y + rx * Math.sin(-a * rad), + res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]]; + } else { + res = [ + ["M", x, y], + ["m", 0, -ry], + ["a", rx, ry, 0, 1, 1, 0, 2 * ry], + ["a", rx, ry, 0, 1, 1, 0, -2 * ry], + ["z"] + ]; + } + res.toString = toString; + return res; + } + var unit2px = Snap._unit2px, + getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx, attr.cy, attr.r); + }, + ellipse: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry); + }, + rect: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry); + }, + image: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height); + }, + line: function (el) { + return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")]; + }, + polyline: function (el) { + return "M" + el.attr("points"); + }, + polygon: function (el) { + return "M" + el.attr("points") + "z"; + }, + deflt: function (el) { + var bbox = el.node.getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }; + function pathToRelative(pathArray) { + var pth = paths(pathArray), + lowerCase = String.prototype.toLowerCase; + if (pth.rel) { + return pathClone(pth.rel); + } + if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) { + pathArray = Snap.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = toString; + pth.rel = pathClone(res); + return res; + } + function pathToAbsolute(pathArray) { + var pth = paths(pathArray); + if (pth.abs) { + return pathClone(pth.abs); + } + if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption + pathArray = Snap.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0, + pa0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + var crz = pathArray.length == 3 && + pathArray[0][0] == "M" && + pathArray[1][0].toUpperCase() == "R" && + pathArray[2][0].toUpperCase() == "Z"; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + pa0 = pa[0]; + if (pa0 != pa0.toUpperCase()) { + r[0] = pa0.toUpperCase(); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +pa[6] + x; + r[7] = +pa[7] + y; + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y].concat(pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + break; + case "O": + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + break; + case "U": + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa0 == "R") { + dots = [x, y].concat(pa.slice(1)); + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + r = ["R"].concat(pa.slice(-2)); + } else if (pa0 == "O") { + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + } else if (pa0 == "U") { + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + pa0 = pa0.toUpperCase(); + if (pa0 != "O") { + switch (r[0]) { + case "Z": + x = +mx; + y = +my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + } + res.toString = toString; + pth.abs = pathClone(res); + return res; + } + function l2c(x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + } + function q2c(x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + } + function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = Snap._.cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4].concat(res); + } else { + res = [m2, m3, m4].concat(res).join().split(","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + } + function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + } + + // Returns bounding box of cubic bezier curve. + // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + // Original version: NISHIO Hirokazu + // Modifications: https://github.com/timo22345 + function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) { + var tvalues = [], + bounds = [[], []], + a, b, c, t, t1, t2, b2ac, sqrtb2ac; + for (var i = 0; i < 2; ++i) { + if (i == 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + if (abs(a) < 1e-12) { + if (abs(b) < 1e-12) { + continue; + } + t = -c / b; + if (0 < t && t < 1) { + tvalues.push(t); + } + continue; + } + b2ac = b * b - 4 * c * a; + sqrtb2ac = math.sqrt(b2ac); + if (b2ac < 0) { + continue; + } + t1 = (-b + sqrtb2ac) / (2 * a); + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + t2 = (-b - sqrtb2ac) / (2 * a); + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + var x, y, j = tvalues.length, + jlen = j, + mt; + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); + bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + + + return { + min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])}, + max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])} + }; + } + + function path2curve(path, path2) { + var pth = !path2 && paths(path); + if (!path2 && pth.curve) { + return pathClone(pth.curve); + } + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d, pcom) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); + break; + case "S": + if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. + nx = d.x * 2 - d.bx; // And reflect the previous + ny = d.y * 2 - d.by; // command's control point relative to the current point. + } + else { // or some else or nothing + nx = d.x; + ny = d.y; + } + path = ["C", nx, ny].concat(path.slice(1)); + break; + case "T": + if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. + d.qx = d.x * 2 - d.qx; // And make a reflection similar + d.qy = d.y * 2 - d.qy; // to case "S". + } + else { // or something else or nothing + d.qx = d.x; + d.qy = d.y; + } + path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"].concat(l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"].concat(l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"].concat(l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved + p2 && (pcoms2[i] = "A"); // the same as above + pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + pcoms1 = [], // path commands of original path p + pcoms2 = [], // path commands of original path p2 + pfirst = "", // temporary holder for original path command + pcom = ""; // holder for previous path command of original path + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] && (pfirst = p[i][0]); // save current path command + + if (pfirst != "C") // C is not saved yet, because it may be result of conversion + { + pcoms1[i] = pfirst; // Save current path command + i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom + } + p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath + + if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command + // which may produce multiple C:s + // so we have to make sure that C is also C in original path + + fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 + + if (p2) { // the same procedures is done to p2 + p2[i] && (pfirst = p2[i][0]); + if (pfirst != "C") { + pcoms2[i] = pfirst; + i && (pcom = pcoms2[i - 1]); + } + p2[i] = processPath(p2[i], attrs2, pcom); + + if (pcoms2[i] != "A" && pfirst == "C") { + pcoms2[i] = "C"; + } + + fixArc(p2, i); + } + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + if (!p2) { + pth.curve = pathClone(p); + } + return p2 ? [p, p2] : p; + } + function mapPath(path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + } + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 == i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 == i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 == i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + // export + Snap.path = paths; + + /*\ + * Snap.path.getTotalLength + [ method ] + ** + * Returns the length of the given path in pixels + ** + - path (string) SVG path string + ** + = (number) length + \*/ + Snap.path.getTotalLength = getTotalLength; + /*\ + * Snap.path.getPointAtLength + [ method ] + ** + * Returns the coordinates of the point located at the given length along the given path + ** + - path (string) SVG path string + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + Snap.path.getPointAtLength = getPointAtLength; + /*\ + * Snap.path.getSubpath + [ method ] + ** + * Returns the subpath of a given path between given start and end lengths + ** + - path (string) SVG path string + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + Snap.path.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + /*\ + * Element.getTotalLength + [ method ] + ** + * Returns the length of the path in pixels (only works for `path` elements) + = (number) length + \*/ + elproto.getTotalLength = function () { + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + }; + // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length? + /*\ + * Element.getPointAtLength + [ method ] + ** + * Returns coordinates of the point located at the given length on the given path (only works for `path` elements) + ** + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + elproto.getPointAtLength = function (length) { + return getPointAtLength(this.attr("d"), length); + }; + // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear. + /*\ + * Element.getSubpath + [ method ] + ** + * Returns subpath of a given element from given start and end lengths (only works for `path` elements) + ** + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + elproto.getSubpath = function (from, to) { + return Snap.path.getSubpath(this.attr("d"), from, to); + }; + Snap._.box = box; + /*\ + * Snap.path.findDotsAtSegment + [ method ] + ** + * Utility method + ** + * Finds dot coordinates on the given cubic beziér curve at the given t + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + - t (number) position on the curve (0..1) + = (object) point information in format: + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o m: { + o x: (number) x coordinate of the left anchor, + o y: (number) y coordinate of the left anchor + o }, + o n: { + o x: (number) x coordinate of the right anchor, + o y: (number) y coordinate of the right anchor + o }, + o start: { + o x: (number) x coordinate of the start of the curve, + o y: (number) y coordinate of the start of the curve + o }, + o end: { + o x: (number) x coordinate of the end of the curve, + o y: (number) y coordinate of the end of the curve + o }, + o alpha: (number) angle of the curve derivative at the point + o } + \*/ + Snap.path.findDotsAtSegment = findDotsAtSegment; + /*\ + * Snap.path.bezierBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given cubic beziér curve + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + * or + - bez (array) array of six points for beziér curve + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.bezierBBox = bezierBBox; + /*\ + * Snap.path.isPointInsideBBox + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside bounding box + - bbox (string) bounding box + - x (string) x coordinate of the point + - y (string) y coordinate of the point + = (boolean) `true` if point is inside + \*/ + Snap.path.isPointInsideBBox = isPointInsideBBox; + Snap.closest = function (x, y, X, Y) { + var r = 100, + b = box(x - r / 2, y - r / 2, r, r), + inside = [], + getter = X[0].hasOwnProperty("x") ? function (i) { + return { + x: X[i].x, + y: X[i].y + }; + } : function (i) { + return { + x: X[i], + y: Y[i] + }; + }, + found = 0; + while (r <= 1e6 && !found) { + for (var i = 0, ii = X.length; i < ii; i++) { + var xy = getter(i); + if (isPointInsideBBox(b, xy.x, xy.y)) { + found++; + inside.push(xy); + break; + } + } + if (!found) { + r *= 2; + b = box(x - r / 2, y - r / 2, r, r) + } + } + if (r == 1e6) { + return; + } + var len = Infinity, + res; + for (i = 0, ii = inside.length; i < ii; i++) { + var l = Snap.len(x, y, inside[i].x, inside[i].y); + if (len > l) { + len = l; + inside[i].len = l; + res = inside[i]; + } + } + return res; + }; + /*\ + * Snap.path.isBBoxIntersect + [ method ] + ** + * Utility method + ** + * Returns `true` if two bounding boxes intersect + - bbox1 (string) first bounding box + - bbox2 (string) second bounding box + = (boolean) `true` if bounding boxes intersect + \*/ + Snap.path.isBBoxIntersect = isBBoxIntersect; + /*\ + * Snap.path.intersection + [ method ] + ** + * Utility method + ** + * Finds intersections of two paths + - path1 (string) path string + - path2 (string) path string + = (array) dots of intersection + o [ + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o t1: (number) t value for segment of path1, + o t2: (number) t value for segment of path2, + o segment1: (number) order number for segment of path1, + o segment2: (number) order number for segment of path2, + o bez1: (array) eight coordinates representing beziér curve for the segment of path1, + o bez2: (array) eight coordinates representing beziér curve for the segment of path2 + o } + o ] + \*/ + Snap.path.intersection = pathIntersection; + Snap.path.intersectionNumber = pathIntersectionNumber; + /*\ + * Snap.path.isPointInside + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside a given closed path. + * + * Note: fill mode doesn’t affect the result of this method. + - path (string) path string + - x (number) x of the point + - y (number) y of the point + = (boolean) `true` if point is inside the path + \*/ + Snap.path.isPointInside = isPointInsidePath; + /*\ + * Snap.path.getBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given path + - path (string) path string + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.getBBox = pathBBox; + Snap.path.get = getPath; + /*\ + * Snap.path.toRelative + [ method ] + ** + * Utility method + ** + * Converts path coordinates into relative values + - path (string) path string + = (array) path string + \*/ + Snap.path.toRelative = pathToRelative; + /*\ + * Snap.path.toAbsolute + [ method ] + ** + * Utility method + ** + * Converts path coordinates into absolute values + - path (string) path string + = (array) path string + \*/ + Snap.path.toAbsolute = pathToAbsolute; + /*\ + * Snap.path.toCubic + [ method ] + ** + * Utility method + ** + * Converts path to a new path where all segments are cubic beziér curves + - pathString (string|array) path string or array of segments + = (array) array of segments + \*/ + Snap.path.toCubic = path2curve; + /*\ + * Snap.path.map + [ method ] + ** + * Transform the path string with the given matrix + - path (string) path string + - matrix (object) see @Matrix + = (string) transformed path string + \*/ + Snap.path.map = mapPath; + Snap.path.toString = toString; + Snap.path.clone = pathClone; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var mmax = Math.max, + mmin = Math.min; + + // Set + var Set = function (items) { + this.items = []; + this.bindings = {}; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i]) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + /*\ + * Set.push + [ method ] + ** + * Adds each argument to the current set + = (object) original element + \*/ + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + /*\ + * Set.pop + [ method ] + ** + * Removes last element and returns it + = (object) element + \*/ + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + /*\ + * Set.forEach + [ method ] + ** + * Executes given function for each element in the set + * + * If the function returns `false`, the loop stops running. + ** + - callback (function) function to run + - thisArg (object) context object for the callback + = (object) Set object + \*/ + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + /*\ + * Set.animate + [ method ] + ** + * Animates each element in set in sync. + * + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + * or + - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]` + > Usage + | // animate all elements in set to radius 10 + | set.animate({r: 10}, 500, mina.easein); + | // or + | // animate first element to radius 10, but second to radius 20 and in different time + | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]); + = (Element) the current element + \*/ + setproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Snap._.Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = easing.dur; + attrs = attrs.attr; + } + var args = arguments; + if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) { + var each = true; + } + var begin, + handler = function () { + if (begin) { + this.b = begin; + } else { + begin = this.b; + } + }, + cb = 0, + set = this, + callbacker = callback && function () { + if (++cb == set.length) { + callback.call(this); + } + }; + return this.forEach(function (el, i) { + eve.once("snap.animcreated." + el.id, handler); + if (each) { + args[i] && el.animate.apply(el, args[i]); + } else { + el.animate(attrs, ms, easing, callbacker); + } + }); + }; + setproto.remove = function () { + while (this.length) { + this.pop().remove(); + } + return this; + }; + /*\ + * Set.bind + [ method ] + ** + * Specifies how to handle a specific attribute when applied + * to a set. + * + ** + - attr (string) attribute name + - callback (function) function to run + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + - eattr (string) attribute on the element to bind the attribute to + = (object) Set object + \*/ + setproto.bind = function (attr, a, b) { + var data = {}; + if (typeof a == "function") { + this.bindings[attr] = a; + } else { + var aname = b || attr; + this.bindings[attr] = function (v) { + data[aname] = v; + a.attr(data); + }; + } + return this; + }; + setproto.attr = function (value) { + var unbound = {}; + for (var k in value) { + if (this.bindings[k]) { + this.bindings[k](value[k]); + } else { + unbound[k] = value[k]; + } + } + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(unbound); + } + return this; + }; + /*\ + * Set.clear + [ method ] + ** + * Removes all elements from the set + \*/ + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + /*\ + * Set.splice + [ method ] + ** + * Removes range of elements from the set + ** + - index (number) position of the deletion + - count (number) number of element to remove + - insertion… (object) #optional elements to insert + = (object) set elements that were deleted + \*/ + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + /*\ + * Set.exclude + [ method ] + ** + * Removes given element from the set + ** + - element (object) element to remove + = (boolean) `true` if object was found and removed from the set + \*/ + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + return false; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + x2 = [], + y2 = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + x2.push(box.x + box.width); + y2.push(box.y + box.height); + } + x = mmin.apply(0, x); + y = mmin.apply(0, y); + x2 = mmax.apply(0, x2); + y2 = mmax.apply(0, y2); + return { + x: x, + y: y, + x2: x2, + y2: y2, + width: x2 - x, + height: y2 - y, + cx: x + (x2 - x) / 2, + cy: y + (y2 - y) / 2 + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Snap\u2018s set"; + }; + setproto.type = "set"; + // export + Snap.Set = Set; + Snap.set = function () { + var set = new Set; + if (arguments.length) { + set.push.apply(set, Array.prototype.slice.call(arguments, 0)); + } + return set; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var names = {}, + reUnit = /[a-z]+$/i, + Str = String; + names.stroke = names.fill = "colour"; + function getEmpty(item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + } + function equaliseTransform(t1, t2, getBBox) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = Snap.parseTransformString(t1) || []; + t2 = Snap.parseTransformString(t2) || []; + var maxlength = Math.max(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + t1 = Snap._.transform2matrix(t1, getBBox()); + t2 = Snap._.transform2matrix(t2, getBBox()); + from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]]; + to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]]; + break; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: path2array(from), + to: path2array(to), + f: getPath(from) + }; + } + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + function getViewBox(val) { + return val.join(" "); + } + function getColour(clr) { + return Snap.rgb(clr[0], clr[1], clr[2]); + } + function getPath(path) { + var k = 0, i, ii, j, jj, out, a, b = []; + for (i = 0, ii = path.length; i < ii; i++) { + out = "["; + a = ['"' + path[i][0] + '"']; + for (j = 1, jj = path[i].length; j < jj; j++) { + a[j] = "val[" + (k++) + "]"; + } + out += a + "]"; + b[i] = out; + } + return Function("val", "return Snap.path.toString.call([" + b + "])"); + } + function path2array(path) { + var out = []; + for (var i = 0, ii = path.length; i < ii; i++) { + for (var j = 1, jj = path[i].length; j < jj; j++) { + out.push(path[i][j]); + } + } + return out; + } + function isNumeric(obj) { + return isFinite(parseFloat(obj)); + } + function arrayEqual(arr1, arr2) { + if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) { + return false; + } + return arr1.toString() == arr2.toString(); + } + Element.prototype.equal = function (name, b) { + return eve("snap.util.equal", this, name, b).firstDefined(); + }; + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this; + if (isNumeric(a) && isNumeric(b)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getNumber + }; + } + if (names[name] == "colour") { + A = Snap.color(a); + B = Snap.color(b); + return { + from: [A.r, A.g, A.b, A.opacity], + to: [B.r, B.g, B.b, B.opacity], + f: getColour + }; + } + if (name == "viewBox") { + A = this.attr(name).vb.split(" ").map(Number); + B = b.split(" ").map(Number); + return { + from: A, + to: B, + f: getViewBox + }; + } + if (name == "transform" || name == "gradientTransform" || name == "patternTransform") { + if (b instanceof Snap.Matrix) { + b = b.toTransformString(); + } + if (!Snap._.rgTransform.test(b)) { + b = Snap._.svgTransform2string(b); + } + return equaliseTransform(a, b, function () { + return el.getBBox(1); + }); + } + if (name == "d" || name == "path") { + A = Snap.path.toCubic(a, b); + return { + from: path2array(A[0]), + to: path2array(A[1]), + f: getPath(A[0]) + }; + } + if (name == "points") { + A = Str(a).split(Snap._.separator); + B = Str(b).split(Snap._.separator); + return { + from: A, + to: B, + f: function (val) { return val; } + }; + } + var aUnit = a.match(reUnit), + bUnit = Str(b).match(reUnit); + if (aUnit && arrayEqual(aUnit, bUnit)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getUnit(aUnit) + }; + } else { + return { + from: this.asPX(name), + to: this.asPX(name, b), + f: getNumber + }; + } + }); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + has = "hasOwnProperty", + supportsTouch = "createTouch" in glob.doc, + events = [ + "click", "dblclick", "mousedown", "mousemove", "mouseout", + "mouseover", "mouseup", "touchstart", "touchmove", "touchend", + "touchcancel" + ], + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + getScroll = function (xy, el) { + var name = xy == "y" ? "scrollTop" : "scrollLeft", + doc = el && el.node ? el.node.ownerDocument : glob.doc; + return doc[name in doc.documentElement ? "documentElement" : "body"][name]; + }, + preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = getScroll("y", element), + scrollX = getScroll("x", element); + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + var x = e.clientX + scrollX, + y = e.clientY + scrollY; + return fn.call(element, e, x, y); + }; + + if (type !== realName) { + obj.addEventListener(type, f, false); + } + + obj.addEventListener(realName, f, false); + + return function () { + if (type !== realName) { + obj.removeEventListener(type, f, false); + } + + obj.removeEventListener(realName, f, false); + return true; + }; + }, + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = getScroll("y"), + scrollX = getScroll("x"), + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches && e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + // glob.win.opera && parent.removeChild(node); + // node.style.display = "none"; + // o = dragi.el.paper.getElementByPoint(x, y); + // node.style.display = display; + // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + Snap.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + eve.off("snap.drag.*." + dragi.el.id); + } + drag = []; + }; + /*\ + * Element.click + [ method ] + ** + * Adds a click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unclick + [ method ] + ** + * Removes a click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.dblclick + [ method ] + ** + * Adds a double click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.undblclick + [ method ] + ** + * Removes a double click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousedown + [ method ] + ** + * Adds a mousedown event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousedown + [ method ] + ** + * Removes a mousedown event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousemove + [ method ] + ** + * Adds a mousemove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousemove + [ method ] + ** + * Removes a mousemove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseout + [ method ] + ** + * Adds a mouseout event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseout + [ method ] + ** + * Removes a mouseout event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseover + [ method ] + ** + * Adds a mouseover event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseover + [ method ] + ** + * Removes a mouseover event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseup + [ method ] + ** + * Adds a mouseup event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseup + [ method ] + ** + * Removes a mouseup event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchstart + [ method ] + ** + * Adds a touchstart event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchstart + [ method ] + ** + * Removes a touchstart event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchmove + [ method ] + ** + * Adds a touchmove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchmove + [ method ] + ** + * Removes a touchmove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchend + [ method ] + ** + * Adds a touchend event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchend + [ method ] + ** + * Removes a touchend event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchcancel + [ method ] + ** + * Adds a touchcancel event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchcancel + [ method ] + ** + * Removes a touchcancel event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + for (var i = events.length; i--;) { + (function (eventName) { + Snap[eventName] = elproto[eventName] = function (fn, scope) { + if (Snap.is(fn, "function")) { + this.events = this.events || []; + this.events.push({ + name: eventName, + f: fn, + unbind: addEvent(this.node || document, eventName, fn, scope || this) + }); + } else { + for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) { + try { + this.events[i].f.call(this); + } catch (e) {} + } + } + return this; + }; + Snap["un" + eventName] = + elproto["un" + eventName] = function (fn) { + var events = this.events || [], + l = events.length; + while (l--) if (events[l].name == eventName && + (events[l].f == fn || !fn)) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + /*\ + * Element.hover + [ method ] + ** + * Adds hover event handlers to the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + - icontext (object) #optional context for hover in handler + - ocontext (object) #optional context for hover out handler + = (object) @Element + \*/ + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + /*\ + * Element.unhover + [ method ] + ** + * Removes hover event handlers from the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + = (object) @Element + \*/ + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture. + // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from? + // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason. + // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID? + /*\ + * Element.drag + [ method ] + ** + * Adds event handlers for an element's drag gesture + ** + - onmove (function) handler for moving + - onstart (function) handler for drag start + - onend (function) handler for drag end + - mcontext (object) #optional context for moving handler + - scontext (object) #optional context for drag start handler + - econtext (object) #optional context for drag end handler + * Additionaly following `drag` events are triggered: `drag.start.<id>` on start, + * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element + * `drag.over.<id>` fires as well. + * + * Start event and start handler are called in specified context or in context of the element with following parameters: + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * Move event and move handler are called in specified context or in context of the element with following parameters: + o dx (number) shift by x from the start point + o dy (number) shift by y from the start point + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * End event and end handler are called in specified context or in context of the element with following parameters: + o event (object) DOM event object + = (object) @Element + \*/ + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + var el = this; + if (!arguments.length) { + var origTransform; + return el.drag(function (dx, dy) { + this.attr({ + transform: origTransform + (origTransform ? "T" : "t") + [dx, dy] + }); + }, function () { + origTransform = this.transform().local; + }); + } + function start(e, x, y) { + (e.originalEvent || e).preventDefault(); + el._drag.x = x; + el._drag.y = y; + el._drag.id = e.identifier; + !drag.length && Snap.mousemove(dragMove).mouseup(dragUp); + drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("snap.drag.start." + el.id, onstart); + onmove && eve.on("snap.drag.move." + el.id, onmove); + onend && eve.on("snap.drag.end." + el.id, onend); + eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e); + } + function init(e, x, y) { + eve("snap.draginit." + el.id, el, e, x, y); + } + eve.on("snap.draginit." + el.id, start); + el._drag = {}; + draggable.push({el: el, start: start, init: init}); + el.mousedown(init); + return el; + }; + /* + * Element.onDragOver + [ method ] + ** + * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id) + - f (function) handler for event, first argument would be the element you are dragging over + \*/ + // elproto.onDragOver = function (f) { + // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id); + // }; + /*\ + * Element.undrag + [ method ] + ** + * Removes all drag event handlers from the given element + \*/ + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].init); + draggable.splice(i, 1); + eve.unbind("snap.drag.*." + this.id); + eve.unbind("snap.draginit." + this.id); + } + !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp); + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + pproto = Paper.prototype, + rgurl = /^\s*url\((.+)\)/, + Str = String, + $ = Snap._.$; + Snap.filter = {}; + /*\ + * Paper.filter + [ method ] + ** + * Creates a `<filter>` element + ** + - filstr (string) SVG fragment of filter provided as a string + = (object) @Element + * Note: It is recommended to use filters embedded into the page inside an empty SVG element. + > Usage + | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + pproto.filter = function (filstr) { + var paper = this; + if (paper.type != "svg") { + paper = paper.paper; + } + var f = Snap.parse(Str(filstr)), + id = Snap._.id(), + width = paper.node.offsetWidth, + height = paper.node.offsetHeight, + filter = $("filter"); + $(filter, { + id: id, + filterUnits: "userSpaceOnUse" + }); + filter.appendChild(f.node); + paper.defs.appendChild(filter); + return new Element(filter); + }; + + eve.on("snap.util.getattr.filter", function () { + eve.stop(); + var p = $(this.node, "filter"); + if (p) { + var match = Str(p).match(rgurl); + return match && Snap.select(match[1]); + } + }); + eve.on("snap.util.attr.filter", function (value) { + if (value instanceof Element && value.type == "filter") { + eve.stop(); + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + id = value.id; + } + $(this.node, { + filter: Snap.url(id) + }); + } + if (!value || value == "none") { + eve.stop(); + this.node.removeAttribute("filter"); + } + }); + /*\ + * Snap.filter.blur + [ method ] + ** + * Returns an SVG markup string for the blur filter + ** + - x (number) amount of horizontal blur, in pixels + - y (number) #optional amount of vertical blur, in pixels + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.blur(5, 10)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.blur = function (x, y) { + if (x == null) { + x = 2; + } + var def = y == null ? x : [x, y]; + return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', { + def: def + }); + }; + Snap.filter.blur.toString = function () { + return this(); + }; + /*\ + * Snap.filter.shadow + [ method ] + ** + * Returns an SVG markup string for the shadow filter + ** + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - blur (number) #optional amount of blur + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * which makes blur default to `4`. Or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - opacity (number) #optional `0..1` opacity of the shadow + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.shadow(0, 2, 3)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.shadow = function (dx, dy, blur, color, opacity) { + if (typeof blur == "string") { + color = blur; + opacity = color; + blur = 4; + } + if (typeof color != "string") { + opacity = color; + color = "#000"; + } + color = color || "#000"; + if (blur == null) { + blur = 4; + } + if (opacity == null) { + opacity = 1; + } + if (dx == null) { + dx = 0; + dy = 2; + } + if (dy == null) { + dy = dx; + } + color = Snap.color(color); + return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', { + color: color, + dx: dx, + dy: dy, + blur: blur, + opacity: opacity + }); + }; + Snap.filter.shadow.toString = function () { + return this(); + }; + /*\ + * Snap.filter.grayscale + [ method ] + ** + * Returns an SVG markup string for the grayscale filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.grayscale = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', { + a: 0.2126 + 0.7874 * (1 - amount), + b: 0.7152 - 0.7152 * (1 - amount), + c: 0.0722 - 0.0722 * (1 - amount), + d: 0.2126 - 0.2126 * (1 - amount), + e: 0.7152 + 0.2848 * (1 - amount), + f: 0.0722 - 0.0722 * (1 - amount), + g: 0.2126 - 0.2126 * (1 - amount), + h: 0.0722 + 0.9278 * (1 - amount) + }); + }; + Snap.filter.grayscale.toString = function () { + return this(); + }; + /*\ + * Snap.filter.sepia + [ method ] + ** + * Returns an SVG markup string for the sepia filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.sepia = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', { + a: 0.393 + 0.607 * (1 - amount), + b: 0.769 - 0.769 * (1 - amount), + c: 0.189 - 0.189 * (1 - amount), + d: 0.349 - 0.349 * (1 - amount), + e: 0.686 + 0.314 * (1 - amount), + f: 0.168 - 0.168 * (1 - amount), + g: 0.272 - 0.272 * (1 - amount), + h: 0.534 - 0.534 * (1 - amount), + i: 0.131 + 0.869 * (1 - amount) + }); + }; + Snap.filter.sepia.toString = function () { + return this(); + }; + /*\ + * Snap.filter.saturate + [ method ] + ** + * Returns an SVG markup string for the saturate filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.saturate = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', { + amount: 1 - amount + }); + }; + Snap.filter.saturate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.hueRotate + [ method ] + ** + * Returns an SVG markup string for the hue-rotate filter + ** + - angle (number) angle of rotation + = (string) filter representation + \*/ + Snap.filter.hueRotate = function (angle) { + angle = angle || 0; + return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', { + angle: angle + }); + }; + Snap.filter.hueRotate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.invert + [ method ] + ** + * Returns an SVG markup string for the invert filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.invert = function (amount) { + if (amount == null) { + amount = 1; + } +// <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" color-interpolation-filters="sRGB"/> + return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: 1 - amount + }); + }; + Snap.filter.invert.toString = function () { + return this(); + }; + /*\ + * Snap.filter.brightness + [ method ] + ** + * Returns an SVG markup string for the brightness filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.brightness = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', { + amount: amount + }); + }; + Snap.filter.brightness.toString = function () { + return this(); + }; + /*\ + * Snap.filter.contrast + [ method ] + ** + * Returns an SVG markup string for the contrast filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.contrast = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: .5 - amount / 2 + }); + }; + Snap.filter.contrast.toString = function () { + return this(); + }; +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var box = Snap._.box, + is = Snap.is, + firstLetter = /^[^a-z]*([tbmlrc])/i, + toString = function () { + return "T" + this.dx + "," + this.dy; + }; + /*\ + * Element.getAlign + [ method ] + ** + * Returns shift needed to align the element relatively to given element. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string + > Usage + | el.transform(el.getAlign(el2, "top")); + * or + | var dy = el.getAlign(el2, "top").dy; + \*/ + Element.prototype.getAlign = function (el, way) { + if (way == null && is(el, "string")) { + way = el; + el = null; + } + el = el || this.paper; + var bx = el.getBBox ? el.getBBox() : box(el), + bb = this.getBBox(), + out = {}; + way = way && way.match(firstLetter); + way = way ? way[1].toLowerCase() : "c"; + switch (way) { + case "t": + out.dx = 0; + out.dy = bx.y - bb.y; + break; + case "b": + out.dx = 0; + out.dy = bx.y2 - bb.y2; + break; + case "m": + out.dx = 0; + out.dy = bx.cy - bb.cy; + break; + case "l": + out.dx = bx.x - bb.x; + out.dy = 0; + break; + case "r": + out.dx = bx.x2 - bb.x2; + out.dy = 0; + break; + default: + out.dx = bx.cx - bb.cx; + out.dy = 0; + break; + } + out.toString = toString; + return out; + }; + /*\ + * Element.align + [ method ] + ** + * Aligns the element relatively to given one via transformation. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object) this element + > Usage + | el.align(el2, "top"); + * or + | el.align("middle"); + \*/ + Element.prototype.align = function (el, way) { + return this.transform("..." + this.getAlign(el, way)); + }; +}); + +return Snap; +})); diff --git a/web/pgadmin/misc/templates/explain/js/explain.js b/web/pgadmin/misc/templates/explain/js/explain.js new file mode 100644 index 0000000..bedc51e --- /dev/null +++ b/web/pgadmin/misc/templates/explain/js/explain.js @@ -0,0 +1,688 @@ +define ( + 'pgadmin.misc.explain', + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'backbone', 'snap.svg'], + function($, _, S, pgAdmin, Backbone, Snap) { + +pgAdmin = pgAdmin || window.pgAdmin || {}; +var pgExplain = pgAdmin.Explain; + +// Snap.svg plug-in to write multitext as image name +Snap.plugin(function (Snap, Element, Paper, glob) { + Paper.prototype.multitext = function (x, y, txt, max_width, attributes) { + var svg = Snap(), + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + isWordBroken = false, + temp = svg.text(0, 0, abc); + + temp.attr(attributes); + + /* + * Find letter width in pixels and + * index from where the text should be broken + */ + var letter_width = temp.getBBox().width / abc.length, + word_break_index = Math.round((max_width / letter_width)) - 1; + + svg.remove(); + + var words = txt.split(" "), + width_so_far = 0, + lines=[], curr_line = '', + /* + * Function to divide string into multiple lines + * and store them in an array if it size crosses + * the max-width boundary. + */ + splitTextInMultiLine = function(leading, so_far, line) { + var l = line.length, + res = []; + + if (l == 0) + return res; + + if (so_far && (so_far + (l * letter_width) > max_width)) { + res.push(leading); + res = res.concat(splitTextInMultiLine('', 0, line)); + } else if (so_far) { + res.push(leading + ' ' + line); + } else { + if (leading) + res.push(leading); + if (line.length > word_break_index + 1) + res.push(line.slice(0, word_break_index) + '-'); + else + res.push(line); + res = res.concat(splitTextInMultiLine('', 0, line.slice(word_break_index))); + } + + return res; + }; + + for (var i = 0; i < words.length; i++) { + var tmpArr = splitTextInMultiLine( + curr_line, width_so_far, words[i] + ); + + if (curr_line) { + lines = lines.slice(0, lines.length - 2); + } + lines = lines.concat(tmpArr); + curr_line = lines[lines.length - 1]; + width_so_far = (curr_line.length * letter_width); + } + + // Create multiple tspan for each string in array + var t = this.text(x,y,lines).attr(attributes); + t.selectAll("tspan:nth-child(n+2)").attr({ + dy: "1.2em", + x: x + }); + return t; + }; +}); + +if (pgAdmin.Explain) + return pgAdmin.Explain; + +var pgExplain = pgAdmin.Explain = { + // Prefix path where images are stored + prefix: '{{ url_for('misc.static', filename='explain/img') }}/' +}; + +/* + * A map which is used to fetch the image to be drawn and + * text which will appear below it + */ +var imageMapper = { + "Aggregate" : { + "image":"ex_aggregate.png", "image_text":"Aggregate" + }, + 'Append' : { + "image":"ex_append.png","image_text":"Append" + }, + "Bitmap Index Scan" : function(data) { + return { + "image":"ex_bmp_index.png", "image_text":data['Index Name'] + }; + }, + "Bitmap Heap Scan" : function(data) { + return {"image":"ex_bmp_heap.png","image_text":data['Relation Name']}; +}, +"BitmapAnd" : {"image":"ex_bmp_and.png","image_text":"Bitmap AND"}, +"BitmapOr" : {"image":"ex_bmp_or.png","image_text":"Bitmap OR"}, +"CTE Scan" : {"image":"ex_cte_scan.png","image_text":"CTE Scan"}, +"Function Scan" : {"image":"ex_result.png","image_text":"Function Scan"}, +"Foreign Scan" : {"image":"ex_foreign_scan.png","image_text":"Foreign Scan"}, +"Gather" : {"image":"ex_gather_motion.png","image_text":"Gather"}, +"Group" : {"image":"ex_group.png","image_text":"Group"}, +"GroupAggregate": {"image":"ex_aggregate.png","image_text":"Group Aggregate"}, +"Hash" : {"image":"ex_hash.png","image_text":"Hash"}, +"Hash Join": function(data) { + if (!data['Join Type']) return {"image":"ex_join.png","image_text":"Join"}; + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_hash_anti_join.png","image_text":"Hash Anti Join"}; + case 'Semi': return {"image":"ex_hash_semi_join.png","image_text":"Hash Semi Join"}; + default: return {"image":"ex_hash.png","image_text":String("Hash " + data['Join Type'] + " Join" )}; + } +}, +"HashAggregate" : {"image":"ex_aggregate.png","image_text":"Hash Aggregate"}, +"Index Only Scan" : function(data) { + return {"image":"ex_index_only_scan.png","image_text":data['Index Name']}; +}, +"Index Scan" : function(data) { + return {"image":"ex_index_scan.png","image_text":data['Index Name']}; +}, +"Index Scan Backword" : {"image":"ex_index_scan.png","image_text":"Index Backward Scan"}, +"Limit" : {"image":"ex_limit.png","image_text":"Limit"}, +"LockRows" : {"image":"ex_lock_rows.png","image_text":"Lock Rows"}, +"Materialize" : {"image":"ex_materialize.png","image_text":"Materialize"}, +"Merge Append": {"image":"ex_merge_append.png","image_text":"Merge Append"}, +"Merge Join": function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_merge_anti_join.png","image_text":"Merge Anti Join"}; + case 'Semi': return {"image":"ex_merge_semi_join.png","image_text":"Merge Semi Join"}; + default: return {"image":"ex_merge.png","image_text":String("Merge " + data['Join Type'] + " Join" )}; + } +}, +"ModifyTable" : function(data) { + switch (data['Operaton']) { + case "insert": return { "image":"ex_insert.png", + "image_text":"Insert" + }; + case "update": return {"image":"ex_update.png","image_text":"Update"}; + case "Delete": return {"image":"ex_delete.png","image_text":"Delete"}; + } +}, +'Nested Loop' : function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_nested_loop_anti_join.png","image_text":"Nested Loop Anti Join"}; + case 'Semi': return {"image":"ex_nested_loop_semi_join.png","image_text":"Nested Loop Semi Join"}; + default: return {"image":"ex_nested.png","image_text":"Nested Loop " + data['Join Type'] + " Join"}; + } +}, +"Recursive Union" : {"image":"ex_recursive_union.png","image_text":"Recursive Union"}, +"Result" : {"image":"ex_result.png","image_text":"Result"}, +"Sample Scan" : {"image":"ex_scan.png","image_text":"Sample Scan"}, +"Scan" : {"image":"ex_scan.png","image_text":"Scan"}, +"Seek" : {"image":"ex_seek.png","image_text":"Seek"}, +"SetOp" : function(data) { + var strategy = data['Strategy'], + command = data['Command']; + + if(strategy == "Hashed") { + if(command.startsWith("Intersect")) { + if(command == "Intersect All") + return {"image":"ex_hash_setop_intersect_all.png","image_text":"Hashed Intersect All"}; + return {"image":"ex_hash_setop_intersect.png","image_text":"Hashed Intersect"}; + } + else if (command.startsWith("Except")) { + if(command == "Except All") + return {"image":"ex_hash_setop_except_all.png","image_text":"Hashed Except All"}; + return {"image":"ex_hash_setop_except.png","image_text":"Hash Except"}; + } + return {"image":"ex_hash_setop_unknown.png","image_text":"Hashed SetOp Unknown"}; + } + return {"image":"ex_setop.png","image_text":"SetOp"}; +}, +"Seq Scan": function(data) { + return {"image":"ex_scan.png","image_text":data['Relation Name']}; +}, +"Subquery Scan" : {"image":"ex_subplan.png","image_text":"SubQuery Scan"}, +"Sort" : {"image":"ex_sort.png","image_text":"Sort"}, +"Tid Scan" : {"image":"ex_tid_scan.png","image_text":"Tid Scan"}, +"Unique" : {"image":"ex_unique.png","image_text":"Unique"}, +"Values Scan" : {"image":"ex_values_scan.png","image_text":"Values Scan"}, +"WindowAgg" : {"image":"ex_window_aggregate.png","image_text":"Window Aggregate"}, +"WorkTable Scan" : {"image":"ex_worktable_scan.png","image_text":"WorkTable Scan"}, +"Undefined" : {"image":"ex_unknown.png","image_text":"Undefined"}, +} + +// Some predefined constants used to calculate image location and its border +var pWIDTH = pHEIGHT = 100. + IMAGE_WIDTH = IMAGE_HEIGHT = 50; +var offsetX = 200, + offsetY = 60; +var ARROW_WIDTH = 10, + ARROW_HEIGHT = 10, + DEFAULT_ARROW_SIZE = 2; +var TXT_ALLIGN = 5, + TXT_SIZE = "15px"; +var TOTAL_WIDTH = undefined, + TOTAL_HEIGHT = undefined; +var xMargin = 25, + yMargin = 25; +var MIN_ZOOM_FACTOR = 0.01, + MAX_ZOOM_FACTOR = 2, + INIT_ZOOM_FACTOR = 1; + ZOOM_RATIO = 0.05; + + +// Backbone model for each plan property of input JSON object +var PlanModel = Backbone.Model.extend({ + defaults: { + "Plans": [], + level: [], + "image": undefined, + "image_text": undefined, + xpos: undefined, + ypos: undefined, + width: pWIDTH, + height: pHEIGHT + }, + parse: function(data) { + var idx = 1, + lvl = data.level = data.level || [idx], + plans = [], + node_type = data['Node Type'], + // Calculating relative xpos of current node from top node + xpos = data.xpos = data.xpos - pWIDTH, + // Calculating relative ypos of current node from top node + ypos = data.ypos, + maxChildWidth = 0; + + data['width'] = pWIDTH; + data['height'] = pHEIGHT; + + /* + * calculating xpos, ypos, width and height if current node is a subplan + */ + if (data['Parent Relationship'] === "SubPlan") { + data['width'] += (xMargin * 2) + (xMargin / 2); + data['height'] += (yMargin * 2); + data['ypos'] += yMargin; + xpos -= xMargin; + ypos += yMargin; + } + + if(node_type.startsWith("(slice")) + node_type = node_type.substring(0,7); + + // Get the image information for current node + var mapperObj = (_.isFunction(imageMapper[node_type]) && + imageMapper[node_type].apply(undefined, [data])) || + imageMapper[node_type] || 'Undefined'; + + data["image"] = mapperObj["image"]; + data["image_text"] = mapperObj["image_text"]; + + // Start calculating xpos, ypos, width and height for child plans if any + if ('Plans' in data) { + + data['width'] += offsetX; + + _.each(data['Plans'], function(p) { + var level = _.clone(lvl), + plan = new PlanModel(); + + level.push(idx); + plan.set(plan.parse(_.extend( + p, { + "level": level, + xpos: xpos - offsetX, + ypos: ypos + }))); + + if (maxChildWidth < plan.get('width')) { + maxChildWidth = plan.get('width'); + } + + var childHeight = plan.get('height'); + + if (idx !== 1) { + data['height'] = data['height'] + childHeight + offsetY; + } else if (childHeight > data['height']) { + data['height'] = childHeight; + } + ypos += childHeight + offsetY; + + plans.push(plan); + idx++; + }); + } + + // Final Width and Height of current node + data['width'] += maxChildWidth; + data['Plans'] = plans; + + return data; + }, + + /* + * Required to parse and include non-default params of + * plan into backbone model + */ + toJSON: function(non_recursive) { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (non_recursive) { + delete res['Plans']; + } else { + var plans = []; + _.each(res['Plans'], function(p) { + plans.push(p.toJSON()); + }); + res['Plans'] = plans; + } + return res; + }, + + // Draw an arrow to parent node + drawPolyLine: function(g, startX, startY, endX, endY, opts, arrowOpts) { + // Calculate end point of first starting straight line (startx1, starty1) + // Calculate start point of 2nd straight line (endx1, endy1) + var midX1 = startX + ((endX - startX) / 3), + midX2 = startX + (2 * ((endX - startX) / 3)); + + //create arrow head + var arrow = g.polygon( + [0, ARROW_HEIGHT, + (ARROW_WIDTH / 2),ARROW_HEIGHT, + (ARROW_HEIGHT / 4), 0, + 0, ARROW_WIDTH] + ).transform("r90"); + var marker = arrow.marker( + 0, 0, ARROW_WIDTH, ARROW_HEIGHT, 0, (ARROW_WIDTH / 2) + ).attr(arrowOpts); + + // First straight line + g.line( + startX, startY, midX1, startY + ).attr(opts); + + // Diagonal line + g.line( + midX1-1, startY, midX2, endY + ).attr(opts); + + // Last straight line + var line = g.line( + midX2, endY, endX, endY + ).attr(opts); + line.attr({markerEnd: marker}) + }, + + // Draw image, its name and its tooltip + draw: function(s, xpos, ypos, pXpos, pYpos, graphContainer, toolTipContainer) { + var g = s.g(); + var currentXpos = xpos + this.get('xpos') , + currentYpos = ypos + this.get('ypos'), + isSubPlan = (this.get('Parent Relationship') === "SubPlan"); + + // Draw the subplan rectangle + if (isSubPlan) { + g.rect( + currentXpos - this.get('width') + pWIDTH + xMargin, + currentYpos - yMargin, + this.get('width') - xMargin, + this.get('height'), 5 + ).attr({ + stroke: '#444444', + 'strokeWidth': 1.2, + fill: 'gray', + fillOpacity: 0.2 + }); + + //provide subplan name + var text = g.text( + currentXpos + pWIDTH - ( this.get('width') / 2) - xMargin, + currentYpos + pHEIGHT - (this.get('height') / 2) - yMargin, + this.get('Subplan Name') + ).attr({ + fontSize: TXT_SIZE, "text-anchor":"start", + fill: 'red' + }); + } + + // Draw the actual image for current node + var image = g.image( + pgExplain.prefix + this.get('image'), + currentXpos + (pWIDTH - IMAGE_WIDTH) / 2, + currentYpos + (pHEIGHT - IMAGE_HEIGHT) / 2, + IMAGE_WIDTH, + IMAGE_HEIGHT + ); + + // Draw tooltip + var image_data = this.toJSON(); + image.mouseover(function(evt){ + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + var tooltip = $('<table></table>',{ + class: "pgadmin-tooltip-table" + }).appendTo(toolTipContainer); + _.each(image_data, function(value,key) { + if(key !== 'image' && key !== 'Plans' && + key !== 'level' && key !== 'image' && + key !== 'image_text' && key !== 'xpos' && + key !== 'ypos' && key !== 'width' && + key !== 'height') { + tooltip.append( '<tr><td class="label explain-tooltip">' + key + '</td><td class="label explain-tooltip-val">' + value + '</td></tr>' ); + }; + }); + + var zoomFactor = graphContainer.data('zoom-factor'); + + // Calculate co-ordinates for tooltip + var toolTipX = ((currentXpos + pWIDTH) * zoomFactor - graphContainer.scrollLeft()); + var toolTipY = ((currentYpos + pHEIGHT) * zoomFactor - graphContainer.scrollTop()); + + // Recalculate x.y if tooltip is going out of screen + if(graphContainer.width() < (toolTipX + toolTipContainer[0].clientWidth)) + toolTipX -= (toolTipContainer[0].clientWidth + (pWIDTH*zoomFactor)); + //if(document.children[0].clientHeight < (toolTipY + toolTipContainer[0].clientHeight)) + if(graphContainer.height() < (toolTipY + toolTipContainer[0].clientHeight)) + toolTipY -= (toolTipContainer[0].clientHeight + ((pHEIGHT/2)*zoomFactor)); + + toolTipX = toolTipX < 0 ? 0 : (toolTipX); + toolTipY = toolTipY < 0 ? 0 : (toolTipY); + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({'opacity': '0.8'}); + toolTipContainer.css('left', toolTipX); + toolTipContainer.css( 'top', toolTipY); + }); + + // Remove tooltip when mouse is out from node's area + image.mouseout(function() { + toolTipContainer.empty(); + toolTipContainer.css({'opacity': '0'}); + toolTipContainer.css('left', 0); + toolTipContainer.css( 'top', 0); + }); + + // Draw text below the node + var label = g.g(); + g.multitext( + currentXpos + (pWIDTH / 2), + currentYpos + pHEIGHT - TXT_ALLIGN, + this.get('image_text'), + 150, + {"font-size": TXT_SIZE ,"text-anchor":"middle"} + ); + + // Draw Arrow to parent only its not the first node + if (!_.isUndefined(pYpos)) { + var startx = currentXpos + pWIDTH; + var starty = currentYpos + (pHEIGHT / 2); + var endx = pXpos - ARROW_WIDTH; + var endy = pYpos + (pHEIGHT / 2); + var start_cost = this.get("Startup Cost"), + total_cost = this.get("Total Cost"); + var arrow_size = DEFAULT_ARROW_SIZE; + // Calculate arrow width according to cost of a particular plan + if(start_cost != undefined && total_cost != undefined) { + var arrow_size = Math.round(Math.log((start_cost+total_cost)/2 + start_cost)); + arrow_size = arrow_size < 1 ? 1 : arrow_size > 10 ? 10 : arrow_size; + } + + + var arrow_view_box = [0, 0, 2*ARROW_WIDTH, 2*ARROW_HEIGHT]; + var opts = {stroke: "#000000", strokeWidth: arrow_size + 1}, + subplanOpts = {stroke: "#866486", strokeWidth: arrow_size + 1}, + arrowOpts = {viewBox: arrow_view_box.join(" ")}; + + // Draw an arrow from current node to its parent + this.drawPolyLine( + g, startx, starty, endx, endy, + isSubPlan ? subplanOpts : opts, arrowOpts + ); + } + + var plans = this.get('Plans'); + + // Draw nodes for current plan's children + _.each(plans, function(p) { + p.draw(s, xpos, ypos, currentXpos, currentYpos, graphContainer, toolTipContainer); + }); + } +}); + +// Main backbone model to store JSON object +var MainPlanModel = Backbone.Model.extend({ + defaults: { + "Plan": undefined, + xpos: 0, + ypos: 0, + }, + initialize: function() { + this.set("Plan", new PlanModel()); + }, + + // Parse the JSON data and fetch its children plans + parse: function(data) { + if (data && 'Plan' in data) { + var plan = this.get("Plan"); + plan.set( + plan.parse( + _.extend( + data['Plan'], { + xpos: 0, + ypos: 0 + }))); + + data['xpos'] = 0; + data['ypos'] = 0; + data['width'] = plan.get('width') + (xMargin * 2); + data['height'] = plan.get('height') + (yMargin * 2); + + delete data['Plan']; + } + + return data; + }, + toJSON: function() { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (res.Plan) { + res.Plan = res.Plan.toJSON(); + } + + return res; + }, + draw: function(s, xpos, ypos, graphContainer, toolTipContainer) { + var g = s.g(); + + //draw the border + g.rect( + 0, 0, this.get('width') - 10, this.get('height') - 10, 5 + ).attr({ + stroke: '#FFEBCD', 'strokeWidth': 1.2, + fill: '#FFF8DC', fillOpacity: 0.5 + }); + + //Fetch total width, height + TOTAL_WIDTH = this.get('width'); + TOTAL_HEIGHT = this.get('height'); + var plan = this.get('Plan'); + + //Draw explain graph + plan.draw(g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer); + } +}); + +// Parse and draw full graphical explain +_.extend( + pgExplain, { + // Assumption container is a jQuery object + DrawJSONPlan: function(container, plan) { + var my_plans = []; + container.empty(); + var curr_zoom_factor = 1.0; + + var zoomArea =$('<div></div>', { + class: 'pg-explain-zoom-area btn-group', + role: 'group' + }).appendTo(container), + zoomInBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom in' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-search-plus' + })), + zoomToNormal = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom to original' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-arrows-alt' + })) + zoomOutBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom out' + }).appendTo(zoomArea).append( + $('<i></i>', { + class: 'fa fa-search-minus' + })); + + // Main div to be drawn all images on + var planDiv = $('<div></div>', + {class: "pgadmin-explain-container"} + ).appendTo(container), + // Div to draw tool-tip on + toolTip = $('<div></div>', + {id: "toolTip", + class: "pgadmin-explain-tooltip" + } + ).appendTo(container); + toolTip.empty(); + planDiv.data('zoom-factor', curr_zoom_factor); + + var w = 0, h = 0, + x = xMargin, h = yMargin; + + _.each(plan, function(p) { + var main_plan = new MainPlanModel(); + + // Parse JSON data to backbone model + main_plan.set(main_plan.parse(p)); + w = main_plan.get('width'); + h = main_plan.get('height'); + + var s = Snap(w, h), + $svg = $(s.node).detach(); + planDiv.append($svg); + + main_plan.draw(s, w - xMargin, yMargin, planDiv, toolTip); + + var initPanelWidth = planDiv.width(), + initPanelHeight = planDiv.height(); + + /* + * Scale graph in case its width is bigger than panel width + * in which the graph is displayed + */ + if(initPanelWidth < w) { + var width_ratio = initPanelWidth / w; + + curr_zoom_factor = width_ratio; + curr_zoom_factor = curr_zoom_factor < MIN_ZOOM_FACTOR ? MIN_ZOOM_FACTOR : curr_zoom_factor; + curr_zoom_factor = curr_zoom_factor > INIT_ZOOM_FACTOR ? INIT_ZOOM_FACTOR : curr_zoom_factor; + + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + } + + zoomInBtn.on('click', function(e){ + curr_zoom_factor = ((curr_zoom_factor + ZOOM_RATIO) > MAX_ZOOM_FACTOR) ? MAX_ZOOM_FACTOR : (curr_zoom_factor + ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomInBtn.blur(); + }); + + zoomOutBtn.on('click', function(e) { + curr_zoom_factor = ((curr_zoom_factor - ZOOM_RATIO) < MIN_ZOOM_FACTOR) ? MIN_ZOOM_FACTOR : (curr_zoom_factor - ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomOutBtn.blur(); + }); + + zoomToNormal.on('click', function(e) { + curr_zoom_factor = INIT_ZOOM_FACTOR; + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomToNormal.blur(); + }); + }); + } + }); + + return pgExplain; +}); diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index 4e08baf..c748900 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -217,3 +217,9 @@ background: #5B9CEF; color: white; } + +.sql-editor-explain { + height: 100%; + width: 100%; + overflow: auto; +} diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index 3e9bc5c..6d777d5 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -1,9 +1,9 @@ define( - ['jquery', 'underscore', 'alertify', 'pgadmin', 'backbone', 'backgrid', 'codemirror', - 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line', - 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter', - 'bootstrap', 'pgadmin.browser', 'wcdocker'], - function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) { + ['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin', 'pgadmin.misc.explain', + 'backbone', 'backgrid', 'codemirror', 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', + 'codemirror/addon/selection/active-line', 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', + 'backgrid.filter', 'bootstrap', 'pgadmin.browser', 'wcdocker'], + function($, _, S, alertify, pgAdmin, pgExplain, Backbone, Backgrid, CodeMirror) { // Some scripts do export their object in the window only. // Generally the one, which do no have AMD support. @@ -160,6 +160,12 @@ define( "click #btn-auto-rollback": "on_auto_rollback", "click #btn-clear-history": "on_clear_history", "click .noclose": 'do_not_close_menu', + "click #btn-explain": "on_explain", + "click #btn-explain-analyze": "on_explain_analyze", + "click #btn-explain-verbose": "on_explain_verbose", + "click #btn-explain-costs": "on_explain_costs", + "click #btn-explain-buffers": "on_explain_buffers", + "click #btn-explain-timing": "on_explain_timing", "change .limit": "on_limit_change" }, @@ -218,10 +224,53 @@ define( '</button>', '<ul class="dropdown-menu dropdown-menu">', '<li>', + '<a id="btn-explain" href="#">', + '<span>{{ _('Explain') }}</span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-analyze" href="#">', + '<span>{{ _('Explain analyze') }}</span>', + '</a>', + '</li>', + '<li class="divider"></li>', + '<li class="dropdown-submenu dropdown-submenu">', + '<a href="#">{{ _('Explain Options') }}</a>', + '<ul class="dropdown-menu">', + '<li>', + '<a id="btn-explain-verbose" href="#" class="noclose">', + '<i class="explain-verbose fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Verbose') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-costs" href="#" class="noclose">', + '<i class="explain-costs fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Costs') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-buffers" href="#" class="noclose">', + '<i class="explain-buffers fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Buffers') }} </span>', + '</a>', + '</li>', + '<li>', + '<a id="btn-explain-timing" href="#" class="noclose">', + '<i class="explain-timing fa fa-check visibility-hidden" aria-hidden="true"></i>', + '<span> {{ _('Timing') }} </span>', + '</a>', + '</li>', + '</ul>', + '</li>', + '<li class="divider"></li>', + '<li>', '<a id="btn-auto-commit" href="#" class="noclose">', '<i class="auto-commit fa fa-check" aria-hidden="true"></i>', '<span> {{ _('Auto Commit') }} </span>', '</a>', + '</li>', + '<li>', '<a id="btn-auto-rollback" href="#" class="noclose">', '<i class="auto-rollback fa fa-check visibility-hidden" aria-hidden="true"></i>', '<span> {{ _('Auto Rollback') }} </span>', @@ -378,7 +427,7 @@ define( height:'100%', isCloseable: false, isPrivate: true, - content: '<div class="sql-editor-explian"></div>' + content: '<div class="sql-editor-explain"></div>' }) var messages = new pgAdmin.Browser.Panel({ @@ -770,6 +819,79 @@ define( self.handler ); }, + + // Callback function for explain button click. + on_explain: function() { + var self = this; + + // Trigger the explain signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain', + self, + self.handler + ); + }, + + // Callback function for explain analyze button click. + on_explain_analyze: function() { + var self = this; + + // Trigger the explain analyze signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-analyze', + self, + self.handler + ); + }, + + // Callback function for explain option "verbose" button click + on_explain_verbose: function() { + var self = this; + + // Trigger the explain "verbose" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-verbose', + self, + self.handler + ); + }, + + // Callback function for explain option "costs" button click + on_explain_costs: function() { + var self = this; + + // Trigger the explain "costs" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-costs', + self, + self.handler + ); + }, + + // Callback function for explain option "buffers" button click + on_explain_buffers: function() { + var self = this; + + // Trigger the explain "buffers" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-buffers', + self, + self.handler + ); + }, + + // Callback function for explain option "timing" button click + on_explain_timing: function() { + var self = this; + + // Trigger the explain "timing" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-timing', + self, + self.handler + ); + }, + do_not_close_menu: function(ev) { ev.stopPropagation(); } @@ -834,6 +956,12 @@ define( self.on('pgadmin-sqleditor:button:download', self._download, self); self.on('pgadmin-sqleditor:button:auto_rollback', self._auto_rollback, self); self.on('pgadmin-sqleditor:button:auto_commit', self._auto_commit, self); + self.on('pgadmin-sqleditor:button:explain', self._explain, self); + self.on('pgadmin-sqleditor:button:explain-analyze', self._explain_analyze, self); + self.on('pgadmin-sqleditor:button:explain-verbose', self._explain_verbose, self); + self.on('pgadmin-sqleditor:button:explain-costs', self._explain_costs, self); + self.on('pgadmin-sqleditor:button:explain-buffers', self._explain_buffers, self); + self.on('pgadmin-sqleditor:button:explain-timing', self._explain_timing, self); if (self.is_query_tool) { self.gridView.query_tool_obj.refresh(); @@ -1083,14 +1211,28 @@ define( // Show message in message and history tab in case of query tool self.total_time = self.get_query_run_time(self.query_start_time, self.query_end_time); - self.update_msg_history(true, "", false); + //self.update_msg_history(true, "", false); var message = 'Total query runtime: ' + self.total_time + '\n' + self.rows_affected + ' rows retrieved.'; $('.sql-editor-message').text(message); - // Add the data to the collection and render the grid. - self.collection.add(data.result, {parse: true}); - self.gridView.render_grid(self.collection, self.columns); - self.gridView.data_output_panel.focus(); + /* Add the data to the collection and render the grid. + * In case of Explain draw the graph on explain panel + * and add json formatted data to collection and render. + */ + var explain_data_array = []; + if('QUERY PLAN' in data.result[0] && _.isObject(data.result[0]['QUERY PLAN'])) { + var explain_data = {'QUERY PLAN' : JSON.stringify(data.result[0]['QUERY PLAN'], null, 2)}; + explain_data_array.push(explain_data); + self.gridView.explain_panel.focus(); + pgExplain.DrawJSONPlan($('.sql-editor-explain'), data.result[0]['QUERY PLAN']); + self.collection.add(explain_data_array, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + } + else { + self.collection.add(data.result, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + self.gridView.data_output_panel.focus(); + } // Hide the loading icon self.trigger('pgadmin-sqleditor:loading-icon:hide'); @@ -1816,16 +1958,11 @@ define( // This function will fetch the sql query from the text box // and execute the query. - _execute: function () { + _execute: function (explain_prefix) { var self = this, sql = '', history_msg = ''; - self.trigger( - 'pgadmin-sqleditor:loading-icon:show', - '{{ _('Initializing the query execution!') }}' - ); - /* If code is selected in the code mirror then execute * the selected part else execute the complete code. */ @@ -1835,6 +1972,17 @@ define( else sql = self.gridView.query_tool_obj.getValue(); + // If it is an empty query, do nothing. + if (sql.length <= 0) return; + + self.trigger( + 'pgadmin-sqleditor:loading-icon:show', + '{{ _('Initializing the query execution!') }}' + ); + + if (explain_prefix != undefined) + sql = explain_prefix + ' ' + sql; + self.query_start_time = new Date(); self.query = sql; self.rows_affected = 0; @@ -2153,6 +2301,66 @@ define( alertify.alert('Auto Commit Error', msg); } }); + }, + + // This function will + _explain: function() { + var self = this; + var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + // No need to check for buffers and timing option value in explain + var explain_query = 'EXPLAIN (FORMAT JSON, ANALYZE OFF, VERBOSE %s, COSTS %s, BUFFERS OFF, TIMING OFF) '; + explain_query = S(explain_query).sprintf(verbose, costs).value(); + self._execute(explain_query); + }, + + // This function will + _explain_analyze: function() { + var self = this;var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var buffers = $('.explain-buffers').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var timing = $('.explain-timing').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + var explain_query = 'Explain (FORMAT JSON, ANALYZE ON, VERBOSE %s, COSTS %s, BUFFERS %s, TIMING %s) '; + explain_query = S(explain_query).sprintf(verbose, costs, buffers, timing).value(); + self._execute(explain_query); + }, + + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + if ($('.explain-verbose').hasClass('visibility-hidden') === true) + $('.explain-verbose').removeClass('visibility-hidden'); + else { + $('.explain-verbose').addClass('visibility-hidden'); + } + }, + + // This function will toggle "costs" option in explain + _explain_costs: function() { + if ($('.explain-costs').hasClass('visibility-hidden') === true) + $('.explain-costs').removeClass('visibility-hidden'); + else { + $('.explain-costs').addClass('visibility-hidden'); + } + }, + + // This function will toggle "buffers" option in explain + _explain_buffers: function() { + if ($('.explain-buffers').hasClass('visibility-hidden') === true) + $('.explain-buffers').removeClass('visibility-hidden'); + else { + $('.explain-buffers').addClass('visibility-hidden'); + } + }, + + // This function will toggle "timing" option in explain + _explain_timing: function() { + if ($('.explain-timing').hasClass('visibility-hidden') === true) + $('.explain-timing').removeClass('visibility-hidden'); + else { + $('.explain-timing').addClass('visibility-hidden'); + } } } ); ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-10 06:51 Sanket Mehta <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-05-10 06:51 UTC (permalink / raw) To: pgadmin-hackers Hi, As previous patch was not applicable to latest pgadmin4 source code, here is the new patch accommodating latest code. Please do review it and send comments. Regards, Sanket Mehta Sr Software engineer Enterprisedb On Mon, May 9, 2016 at 11:56 PM, Sanket Mehta <[email protected] > wrote: > Hi, > > Please ignore previous patch as there was an error in it. > > Error: > Tooltip was not getting disappear when user moves cursor out of image. > > I have attached a proper patch with this mail. > Please consider it for testing. > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > > On Mon, May 9, 2016 at 8:49 PM, Sanket Mehta < > [email protected]> wrote: > >> Hi, >> >> PFA revised patch according to Ashesh's comments. >> Please find my response inline. >> >> I am currently adding minimap feature in graphical explain. >> I will send a new patch for the same. >> >> Regards, >> Sanket Mehta >> Sr Software engineer >> Enterprisedb >> >> On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi < >> [email protected]> wrote: >> >>> Hi Sanket, >>> >>> Please find the review comments. >>> - Please add the missing 'explain.css'. >>> >> Done >> >>> - The application should be smart enough to handle conflict in options. >>> i.e. >>> Buffer is not a valid options without EXPLAIN ANALYZE. >>> >> Done >> >>> - A statement having EXPLAIN keywords with different format should at >>> least render the output in the data-grid. >>> i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; >>> >> Done >> >>> - Please use the keywords used in the EXPLAIN statement in capital. >>> >> Done >> >>> - Explain should not work with empty string. >>> >> Done >> >>> - Font size in the tooltip is very small. >>> >> Done >> >>> >>> >> - Smoothing the zoom functionality. >>> >> Minimap will be added and zoom functionality will be removed. So it is >> ignored. >> >> - Arrow marker is hardly visible. >>> >> Done. >> >>> >>> >>> -- >>> >>> Thanks & Regards, >>> >>> Ashesh Vashi >>> EnterpriseDB INDIA: Enterprise PostgreSQL Company >>> <http://www.enterprisedb.com; >>> >>> >>> *http://www.linkedin.com/in/asheshvashi* >>> <http://www.linkedin.com/in/asheshvashi; >>> >>> On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < >>> [email protected]> wrote: >>> >>>> Hi, >>>> >>>> This patch includes the patch sent earlier for stand alone graphical >>>> explain. >>>> >>>> And also "horizontal lines are not proper" bug is fixed in the same >>>> which was reported by Dave in previous patch. >>>> >>>> Regards, >>>> Sanket Mehta >>>> Sr Software engineer >>>> Enterprisedb >>>> >>>> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >>>> [email protected]> wrote: >>>> >>>>> Hi Team, >>>>> >>>>> PFA the first patch for graphical explain integrated in sql editor. >>>>> >>>>> Below are the few things which are different from previous patch which >>>>> was sent for stand alone graphical explain. >>>>> >>>>> - Now user can select Explain/Explain Analyze with four optional >>>>> properties (Verbose, costs, timing and buffers) >>>>> >>>>> - Initially graph will be scale (according to only its width not >>>>> height) to fit to screen so no blank space will be there in case of very >>>>> large graph. >>>>> >>>>> - Along with zoom in/out button, "zoom to original" button is also >>>>> provided, by clicking on which graph will be scale to its original size >>>>> (not same as initial one which is according to screen size). >>>>> >>>>> Please do review this patch and let me know in case you have any >>>>> comments. >>>>> >>>>> >>>>> Regards, >>>>> Sanket Mehta >>>>> Sr Software engineer >>>>> Enterprisedb >>>>> >>>> >>>> >>> >> > -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] integrated_graphical_explainV5.patch (483.8K, 3-integrated_graphical_explainV5.patch) download | inline diff: diff --git a/libraries.txt b/libraries.txt index 9fcf755..ad1c004 100644 --- a/libraries.txt +++ b/libraries.txt @@ -27,3 +27,4 @@ backgrid-filter 01b2b21 MIT https://github.com/wyuenho/backgrid backbone.paginator 2.0.3 MIT http://github.com/backbone-paginator/backbone.paginator backgrid-paginator 03632df MIT https://github.com/wyuenho/backgrid-paginator backgrid-select-all 1a00053 MIT https://github.com/wyuenho/backgrid-select-all +Snap.svg 0.4.1 APACHE http://snapsvg.io/ diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index f461cbe..33c693e 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -6,28 +6,59 @@ # This software is released under the PostgreSQL Licence # ########################################################################## - """A blueprint module providing utility functions for the application.""" -import datetime -from flask import session, current_app +from flask import url_for, render_template from pgadmin.utils import PgAdminModule import pgadmin.utils.driver as driver +import config MODULE_NAME = 'misc' -# Initialise the module -blueprint = PgAdminModule(MODULE_NAME, __name__, - url_prefix='') +class MiscModule(PgAdminModule): -########################################################################## -# A special URL used to "ping" the server -########################################################################## + def get_own_javascripts(self): + scripts = [{ + 'name': 'pgadmin.misc.explain', + 'path': url_for('misc.index') + 'explain/explain', + 'preloaded': False + },{ + 'name': 'snap.svg', + 'path': url_for( + 'misc.static', filename='explain/js/' + ( + 'snap.svg' if config.DEBUG else 'snap.svg-min' + )), + 'preloaded': False + }] + return scripts + + def get_own_stylesheets(self): + stylesheets = [] + stylesheets.append(url_for('misc.static', filename='explain/css/explain.css')) + return stylesheets + # Initialise the module +blueprint = MiscModule(MODULE_NAME, __name__, static_url_path="/static") + + ########################################################################## + # A special URL used to "ping" the server + ########################################################################## + [email protected]("/") +def index(): + return '' @blueprint.route("/ping", methods=('get', 'post')) def ping(): - """Generate a "PING" response to indicate that the server is alive.""" - driver.ping() + driver.ping() + +def demo(): + return render_template('demo_explain.html') + [email protected]("/explain/explain.js") +def explain_js(): + return render_template("explain/js/explain.js") - return "PING" [email protected]("/sample") +def sample(): + return render_template('sample.html') diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css new file mode 100644 index 0000000..49a4bc4 --- /dev/null +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -0,0 +1,56 @@ +.pg-explain-zoom-area { + position: absolute; + top: 5px; + left: 5px; + opacity: 0.5; + cursor: pointer; +} + +.pg-explain-zoom-btn { + top: 5px; + min-width: 25px; + cursor: pointer; + border: 1px solid transparent; +} + +.pg-explain-zoom-area:hover { + opacity: 1; +} + +.explain-tooltip { + display: table-cell; + text-align: left; + white-space: nowrap; + line-height: 10px !important; + padding: 2px !important; + font-size: small; +} + +td.explain-tooltip-val { + display: table-cell; + text-align: left; + white-space: pre-wrap; + font-size: smaller; +} + +.pgadmin-explain-tooltip { + position: absolute; + padding:5px; + border: 1px solid white; + opacity:0; + color: cornsilk; + background-color: #010125; +} + +.pgadmin-tooltip-table { + border-collapse: collapse; + border-spacing: 1px; + top: auto; + left: auto; +} + +.pgadmin-explain-container { + height: 100%; + width: 100%; + overflow: auto; +} \ No newline at end of file diff --git a/web/pgadmin/misc/static/explain/img/ex_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe75d909f5092c4d3ba8978c75fbc57d7f606d GIT binary patch literal 574 zcmV-E0>S->P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10lP^=K~!jg?U_w#!!Qs=pNrR76nc`JAiEyfyPUu$F?5lg!9`tE zrVdorjI6O#*B=N1Q4~GTk7uODImZ$7QhEcqbb{2T!+^AsNlnvqz}0v!OZCpVcg+u) zSl03oH-ylcGy!)Fj09u=UN>$mMIX+&H|b<ajP!gzp{f<N2t38e1(}OYz(X)^Z9SDm zaL$Pb&;cXx85twc3D+9}YYwWtX(n61tgLAZVhA&A0ZDox`m}f_o&;Lp=3^|TZAm4? zB8D-uw2Hk&77xL~GD+H8Yh{L+-D~onRU64N$mC{z9Z`Z<4$%uyDn(tUuBBqiTE>@* zne6>YDVVIT^|Y|u&2%+YKxQ4H!ZKN8+Uk0kwJKPjW&<(>@$PjAe4RCOnSn%Nr0(=P zYi|fJ04V_hnL$cH0K3&%;sz_V=BgQD)cm$)2vvhs6@*_isdrBfc8kD{yg=7gktITF z+PGFu2!0OeLWgu>5LFp3D9xourL!bQu%a?wd{rRqFIvi++{=Q!&>aaV%KTa{dS;2c z$5o3IhEOTyT37x61pK30-JX4KbAS7Pk<5;R_SRus>jbGyCrEAj0!#X?PWurOy8r+H M07*qoM6N<$f>VU-$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_append.png b/web/pgadmin/misc/static/explain/img/ex_append.png new file mode 100644 index 0000000000000000000000000000000000000000..017a2068b735f13cb89a3bcb2832e5880d17df56 GIT binary patch literal 1162 zcmV;51a<p~P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(LcQrnzUg(&?|IPgRl@0p)bM7=>}tvEZ_4YI+3|bM?Sj$mrrz?7)b5hj z@2}zW1*hRn!RZ^W<6Fh+V#n(^x8+d2=WEC4a+aaNk2du1$nfm9@9MSh>9q3g#qH&> z?c}iR<FN7S!|>?B>));G-mL1~tMBB$>*k;D>$d6On&{t|?&h=S+m`0ol<eWI<I<1f z(2eQZsp{jL=-rs*){^1Oi|N^?<kgYn(~#oMjOf><@94Ab;k?JHb@1lE=hUR;)1&O& zx!}r)-o=I9!-U<zg67eo-^hpM&!OhgqTIiL<j$Y(=D_CCqwCqW<jtPr%%0=Rp4+{D z+PZy)sbo@(8Kui)sL*Ju)oiZXakAicwdHz}mC<Hv(aX&7yuR$dzwOS>^3l=q!NTst z#P8G8^VQY#$jI=?$??j|@!8t--ro1u*Y)Ay_q@IAr>W+ss^`DI?yaxsud(UH#qY<+ z@3pq;x47%Lx$M-`^vB2WiI(>{00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0zpYcK~zY`?U3tJ5>Xh&?SzGeqJ$LLD=fGO%SB*ek((>YO)i2W3vOk#CSYi4 znRfSIZ+9mfuyZIJXZldjhj-?kd4K0Q&oeUeU#e~(MZ}3i&`phI^cK3U)oRDk*qyt& zaWp=m*H5C!DTCo2!Xg@@(Kw2xO(xTQ^uTO3>(InQtyYhwW@dB-G{|N8&s`p=e<n^G z0<#v2W%goPDar;m`yB0nd8dnU0~WD(JRXZWy+HYV3x2Q%f<YFXp-`9`j6@<<8Ch7g z109S;oxp^{vG^dw8;L|H@Gk}eG_cV`k^ych7US{Aj}#QOtfZjT6pWn09q0KJ7I_Sc zh!gMP^;&1a=J(qj;9yzj3b;8go`O_5oyp=qCa3T%U!+JRLvo5(EXPASzgj5bk-lP+ zO0n@=u9Sw%YN1djA(xBgOQn1U)(VwM6_42b_BpvF*6CW8Q^eI2nT;%D%hhV_+8T4v zEISV?48yr0#q(+T{k3Ab2DQz)fOi2p8cn$56iaG~e0~Fpl}e)u^=7jv;1M>FxKwPp z(r9dgKt_How%TaO#{-achU4Ux__UIuSXNThl@v8W5U#DUt7}W#B5ow&NzYaPMkJm- z`+3#B5v1H~KNqnZ(M8-Adt7=qvQOWu;_p1vqZcA^BYthzl84euNfB}45NYSt?ruwJ zclP#POWpm0H;2+;tKB}5j=J6Bw-Oe4cXIOnRO+0aefTJS`uyeVj?_BsblTFl^ZkS4 zzljW=<qD1clll(R-{b2g;$(6F001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@z zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUh cIxsdXFf}?bFv^!ztN;K207*qoM6N<$g1#AbUjP6A literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_and.png b/web/pgadmin/misc/static/explain/img/ex_bmp_and.png new file mode 100644 index 0000000000000000000000000000000000000000..64d5869dcfcf9d94d031fa068cff93ea929180b2 GIT binary patch literal 1006 zcmV<K0}=d*P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004)P)t-smD2kF z003rd(R6flb#--ic6N7ncY1nyHi*G{dwYC*e13j@fPjF4f`WsCgM@^HhlhuVh=_}e zi;azqj*gCGmC%omkC2d%k&%&&j=z$UlEIHQm6er`lHGcqshOFXoSdAVo}QbW#Gjv^ zrlzK+r>D86a;T`NPQK>5s&lKWtGldpyRCMut*u(Y=dP}<ys&q#udltad8@4GzOs6W zx!ba`vSh{Rx3{;mwCZuo?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?Zd;v-NJ*w!S2S! z#*5VM-^PaD$cK{E@5aaP;L3^0%F2}3@Z-y#<IJAq&7R`WjpWXs%+2x5&hq8Zq2|$| z)6>(Y-ty(vljhW<)z#JK)upZ9^VHPy=+~y`*Qe^(w&~ia>DsB<+S=*ds_NXT>)W{8 z+}z#W-Rs`0?A^KE-rnrst?b~g?cclJ-uCR`ui@e0?BlTF;^Ob*zvboS@aDkq=fUUa z=jrL`@$1Cu>gw?D@bU5S^78WY^Yiuf_4fAm`1ttw`T70*{r~^}C9&%N00001bW%=J z06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0q;pfK~zY`?UY$l6G0S(b8}-Di3kcP z+Oo)^h$4bwltoqvL?DD{Mjf_nBqD~O2?A~ymixDzo*9a*Gm})MC?7Zv{c`K8Gv{>Q zvDq$ko~o9(s?QF(wL!N4k*52GJqwax@WJEtiUu~Rr}eShD?&VOcaK*pj!Vugb=sg# zfY{%@e)DeKes;iqrqk&yCPD_D!r-C^Nk4<GWMRlx_z0E==`xVDE_fnFj<OJC>PwuJ zQ#!=9lF84TBBa*NRjVOi9LP1IA^nW2-@@fKw*1L<;8opaGaip`h_l>+MlB1G6SG9S z=+u$;BX}4UBk&Ro<O=>E`h+(O1ZE*><<f@Dv{HsEI<ou#?nSH``|ZN(SURV-%r>Ht zNXoo1qP+&hYdgl><kJ{stMHBkrzooyKsJ^Ng_cqlS=#YAjp3zO3@bPinuH0(v@xPG z-th~(T!n2MS(<=x#ngpg%P%#>ef9pot6A9mcrN5H3(-xi$?R{pAeQfQB&8_Is%c|H zG5v{QDc(Jx{2HTgO)iJ4;r-tV>{PR?%CelW*cUn`^~2;*7z$c$rLkbz!Q>%$6)bF# zgDMhW1^r<X!9XBkv6Uy4*H)f(3HbeC^EY-H@%KXSjQLiI5MN;~GdYo*S;9V_FI=R? cF7zMiA0?@qIju>9W&i*H07*qoM6N<$f<qfLO8@`> literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png new file mode 100644 index 0000000000000000000000000000000000000000..2657d8c39328bfc80751c60db9d3ab4341c0de35 GIT binary patch literal 1106 zcmV-Y1g-mtP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s00000 z003rd(Nc{WHi*Gol_FY@Wn`8)38~@|tKwvp&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPGu5^~NHbTAWN5AP#zUE86=}y7vTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q^_*?AyJGyuIvu(eH!N?S#?pz`^c> z)9|d;ZHv_Ik=5>!)$gv_amL5*l-Tf>+3~XAcCFUw%+2wj+wtexE9lxP&Cc@b+bZna zD(>4V@7yZ!+$!?iD)ihcx!dfw=Y00vDy`r1`Q0h{-6_=6^RD3Y``#)1-YNdxDZbwA zx$A$x-|oWT?z`@S?c-qY<6p($@9^Ybyzqqb<X`jTU&rI{$m8(y<zMvWU&`a~_2pmp z<zM*aU(4k2-rn~3=3n~eU(Mz6{N`W&=3mk0^3&+^^6H1w>GRa-^z`e8*6H;2>xcO3 zhu7-$`s|1O?1ujAhT-q`mEcQQ00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94 zoEQKA0&7V`K~zY`?Ud_N(?Ar(NfQ+@uBZsUQR*A(3k7^uiA_xlwb7<XX$T2Wl46zw z3Z<omf1TZggd}Y;GR`=D;C$H3?B=&;&b@cGr{_ffM12%iU&sC(Yu~pzN7RRBuO_}z z9SHSg=<4;C)SHp}k3Ldg#wI3zy8lp*uid=+whJ=U+k5r~HGFAc;3+jWJaTW6`U{t^ zEElbP-|8I2KEHnd^>^&(-vmu3&<E7Y<#G+wL{Y4Rx+F<;;36;16PJH@5PE-~#z=W; ziYWt;VNw#1SeBJN2=S2cA-lUa!Z3^o#8j#a5_H+w@gP!)Wi2G_L4sKv#G9fn%W}g- z`eRt9$y)*BIl%I*K9?(GoOF@xZQI4ZUy^0CDl3(yC(CW(0vV5!j_A!z8h-}~mT*$6 za2%)l5JX@-7#$sd_le%vpcj!ymO#PfbULko3dd#C2p5DnE;2^GRe;K6G8zcaf)Jd= zPSH>*C`D7%v}T}UXUKCdvcCQ&74!AQMsP2b2D)EWk&C8PTM^wqM7$}qY%Zrq%-GtR zg(zuUST%!@YA%<95iYB%7Gn28&1ADxp!<=IEX&Il;!V+l5Vj&_Y-#D(Gq$jB=z@FE z)OFo<X@_?I6h_E^1__=pLT79oBQrC<=I0lWMDj$zh?ucbsf$a&>(Y@0AyyV$hfa#N zVHoX*8Jn9s_Kewxb3cRzb}`Mpu<oOWZ+aR(egNk4c?ck1K*3ExD4Jn2MsLj~le1g2 zh42s<1wlYavFJkrE~R9$WV`UZ0SrM9%pelTlE5>D9%WyOJ=2@Tu2_G^GagZ~6a9ZW Y0Mz-{B6#`Cr~m)}07*qoM6N<$f){{JGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_index.png b/web/pgadmin/misc/static/explain/img/ex_bmp_index.png new file mode 100644 index 0000000000000000000000000000000000000000..23b9733b56792533e4db25ca9890a0a0140c6ff9 GIT binary patch literal 1172 zcmV;F1Z(?=P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004@P)t-s000{R z003rd(Nc{WHi*Gol_FY@Wn`8)45{LDla^$a&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPPu{MmZbjzYxL%irozv)iC=1#%sTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q|V#etORA+r5d~zJR>F?0eDg-NAx` z(d~rM?%l(Kz`^c>)9|d;ZQjL&i`4Gl$A^*C?%>FXlGX37+HuCm@8HUbl-Tg$%!-%U z@#4;m<IJA2;C8Ln>CDaX<<6kv(T?ZZE6vXG=Fy>}-SXtrk>=B+^4u!t)TFuF?6>E9 zt>5$1)bp<3^XA!==+~zI-YMzWr@r3px$A%D+?T-L?&;d7!r<=c-k9s!x9Z%g?c-qY z<6p($@9N#Gyzqqc<X`FGo9x}X$K&wG<M7Jk@a*8N%jEIi-uC(CU(Mz6?BlTi=3nmO zz3t_((dY8+=Caf1^Y7)q^6H1w>GRa-^w#P0@aMtr>9p7C_3`P${_KYG?Z)Bn_g>Mo zbpQYW0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_00N9jL_t(Y$L*BsQxZ`a zhh26nvhB^vO1oLo-JmFv5|N5XBA|_nRxB8D7XcMR7F@v#0{+$QVK1_a?Bq1l^uhPT z*_pHZ%x|7^ezOAuC-YBckU%rovwx?vFI&Y|#D{0EroRzA2=QcObo3?hX8iu6kHpu> z>6stWH^k%XH}AeZ0vXY2wKs^dOT)uYiOI3?do#per1Wz++u7&Wi~K6S(tLjX{>v}T z;kSB{)N>E0r_<>=v>S~^8`><(wn0K(oX0MI??T9f0}>%=uh*M~Mn0c!0Gmiet6d28 z5R)PM`wD~wHX4nVRZ@0$Wk@2yLNyu+bs<U@5fNNE7R_?GyeA<;8Z@WzTMFbFpyAi& z{3=ViitBI*+1Zh$RI5#B7K_EbE|=Tb1ze}Y#UZ!0Nc6mdd9k!$QS|wISsB6+XdX;V zOuhR=Zf=sx+~8h})31g?q2dvUJcUEVlnj&w#N$ape-{qnT{4-vU{TAaQZ>biox#sZ z$i~K>oS5uhcm(RXT&@m##cZ|)wNxxtQMr8q$pr#|oL~`iI2^P}$JW;+qy$+HkJ#<B zO3K=rgfNiu%+AIjVz=9ZDji#0?I5jEsnmj63|UlYnl7kxY-Q!x9a~xwQW&NMl}LoH zKp`0P7y91*DTMI1AI2EY!p2zyEfzD?w_{TXnV<i;jEAu>1GLR%4T9fnRv_|@#p7Km zwAE@sh{;5$bc{nfE(~(vEeaGxB~?1MxOnW2@ran>r>FuX-EMcX-|cfhzPUN{^8+Rv z=Ja_Bx6xp5_UjnAz2I^!Y?C5FnM@`(xD9edkrH>g;)f}e$!P3B6fSzyF}>u%TO^%M mr}D&xdVb?7Cw4Ob-~0w&gyX$CR{j?N0000<MNUMnLSTYde~VB6 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_or.png b/web/pgadmin/misc/static/explain/img/ex_bmp_or.png new file mode 100644 index 0000000000000000000000000000000000000000..c22fc31eee32e53abf634278f9d57751181f15c0 GIT binary patch literal 685 zcmV;e0#f~nP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700030P)t-s00000 z003B6SY~U{Hi*GwmC%ijzrl|-kCNSbo~fFenwy-&xu<eYzUI5CbGxi`yRCLw!RNfN zcfGNBtE}k0vU-WR+hoP)v$X2Ey1H@8?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?cKtI zz`^c|)b8KLhTq7ClGX3V$M4|EiImvz<IA4o%%0@Up5oAr<j$YW&GF67^3l=J<<Oz# z(W0i_^5xc(=G3I;)upZ9^VHPy=+~y`*Qe^(w&~ia>DsC3+^Xu_s_Wah>)x#F-MQ@G zt?b~g?cclJ-uCR`uk7Qn@8rMa<mB+?!0_k6@$1Cw?CkIF@AUNa|NsAqxAFG?0004W zQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkPM@d9MR7l6|)NN0KU=#*mj$o+0 zXGv;SRwxw`6%>^SK@x>8z5V~+lCW40^I>$hY<=+l#CCS=?A!_rGtXZp&xOfP4=T~1 zLLuDg&VhK#Q3h9{B+&*8S6f~eBpML~p(b&^vn6@U$0T2m#b{8Z5cd4&_~MEE7O~-9 zf*=_4G_tn|`*$&UE0u;Z3AUi@Ws_kpcNvpsxCSJ7EW-w!ByJ(e*z+DnG*V#06sAdo z57R(x899zKpx?3pi_}}3HCVOj1h#=r;0$csmirZ0vT%(JY|HXz-k5KiT_1Ogc>-+% z*I2g=Ed#gZrj<t0Z!rv`Kl8@=x~{vp_eDR1riLU<*hLa;LR4I1uBNJPc4P0=>MO1> z^3%t=s-pBVfBn$JPrOoxdMEQgMkXTi54I4blS&e|kfbNeaxb$nGU<)Y^N;cg@O4qi TF88uo00000NkvXXu0mjfLbGwY literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..e99f57478842f61cf0582433b659d37f0c532d5c GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_@3?!2S6O@1yXMj(LE06{PXIHn!e64$cEXI-` zzhDN3XE)M-9L@rd$YLPv0mg18v+aP48c!F;5RLO&CtC9zP~dS+JaMn}cL58V&ewnH znS#1o7niJ>^>*TX*`QzgMdD7POzPaTo+w<9uwpLL)1F%W#!IqdhoMSxhwp~0@cf02 zhkMjmROfZc`EZ)w`S;|i<*e@Qr8gQ^@9R11|6Rc8|AQ9IRLjSmUOFeWtM)%%ZozPh zRpl$&!*g?h?ocgpjVMV;EJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0 rRpn4L<mRVjrd2{T7+8WefK*!<m_an0njX3asDZ)L)z4*}Q$iB}@40B! literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_cte_scan.png b/web/pgadmin/misc/static/explain/img/ex_cte_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1d779372f7fd212d2096e7701b0f1af05a5297 GIT binary patch literal 1955 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_delete.png b/web/pgadmin/misc/static/explain/img/ex_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ca051cd5d01ee2f3ac17779b362999d82a9285b5 GIT binary patch literal 1129 zcmV-v1eW`WP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003^P)t-sKLD^> zTU+Qs2lh=8Hi*I5b0^MyED5RN(19;<mZ6f8lEIHQ*N;guwdHlD$Lf$-LA>b8qFCae zX-dH9$EtPXqi$Wq>SM<0Ysctl$n0**>~+oT+Pi++y?@)iiQK+`+`oW((eK>Bf`rlT z-NS=~)9~KJgx<x4-o}QE)b8KMhu_GEk=5?t$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc z&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+mlIGK+<<^tt)THOtrLN%f=Gm0!*QV&# zr{>z0>DZ^~*{J8-m+9K6>e;sG+p6o@x9HxP>fNgB+_>rBn(N-I?A^NS->vN4y6oVs z>f@a4-@EMLuI=Ev>g1j5;;-%DyzJw!?d7rW<i73ZvhL=y@8!Vo=D_dhv+wD(@aV$u z>B8{rw(;x4^6ka*?Z)%)$Yy(c-~a#s0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkV znw%H_00Om1L_t(Y$L*8bdl^v_#f8bG-PLL%nhMc~q#`mQ2qBD7)FomPgc62MQMdg6 zk3DnFFeXNthkjrCko~Zp{O0Vn_M*|e%s-g7lsHRO4WY~igJFl-+ccRDsDn>t^C@+@ zx4(Z*ogcZ~Uny0@u)e--pf-`3sE>NR-c0Qve4jen-Zs0bzx2v0yz^33L*QXJ96n67 z-|vrMEC|8~Mm*0Cfcyr)IFAhP?`wTY`?t5ZJrIhyTpRdgGF}BjOnw=S3Z#aS8bOKz z2)SI2hh{Q9MZQla-3-V`zlMK|wO1@6q@DYg<e?sq#VQh#$r!5>kiFpjXD)tV7tH|- zs+Ce#@?tf9p@%c(J&3b~b$3yv?^<i0Wd?NOY>az?FosdP&5vMEuU5Oz<v6Z0{jh=o zomQ*WZOAT~qKnHCa6!L6FYiCcNQh7@l3<f{sKzcYIN<z#Z+<Q&%wTg<1P9CGU@I5F zAO{7nm(GGl$rxFfd0BMP$!D`Im_IsL#iN4e&4xICNNma=3fVzdXx0akb}J=xi%ub* z??5Y^PBlQ;M@VO0uV|$Gl`d%HB7Jh~V&PGT0ag%FkH=9lh;qT8zW{lfrqhr*b~zs- z5-3Jml9U9SrB6;$kZ?Mkj5>n$=YC2mx@aL6sYC-BEW?yl5z?^_b4}Y?mYDns#}ztj z_&TfPMvVl^-a$DU3E!wMhWB5?9atqzKrRj$h&b%_kUD~kp+H#Yp(6@myWO?~!I3Hu z=Fs5?L&$Ek1=NvFHk)oKyp$u6@HJeA0)gu%65GN}d$-s()mK`n1iAvzJBEpt;U*Lc zp;rPv-<A4eq!>gQ2X<i-UHB{(%b7ZoaEZkr8pXlNh({e^(G{YSM(iRIu-Pm=I9ra~ vF;TQX(RmkF9*^hhiNtoF^RIlF|7m^$H0#Fus?kFU00000NkvXXu0mjfhwW63 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..acba49c4fbfd9b871444c9e8d528deda3a37dda4 GIT binary patch literal 1607 zcmV-N2Dtf&P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70008nP)t-sG*MJ9 zGc__jJu5&&G(JByKR_-+M?XVFIz>f0Mn*qMOEFGSGEh=NO-@KmPBl_hNli~gPftZq zP)koyMp05tQdB!wTT50~PFY$|TU$Y2VNhILLSSN1U0qaQU`J$UR$*dSVq;iiWJzag zS!88eWoBDuXIy7!VrOYyX=+bxa9?U`N^o*kZE<F6ZD(t4VQp?xadcvCZ%%Y}V{dR| zaB*dEa$s|EW^!|FadcC8dv0=dXmoXNb9QNUb!&Hbba;Drd3JAmdn|~-V1I&kdwy7h zihX~4b%B9*gM(g*ka&cIdWMF3hlhNKh<J;Neu|2OiHrcK<9Cjd0IB7GjE#bhkBE(s z0IuVSj**0rkpQseg^`kdl$eK;lx>#JkCT>(m6nQ@mx7s{gPNXfp{9hJpNE^8j+&cS zs;iQopNycNF}3BKo|}xLs5H0djijkIxapRrteK{!prxpqr>9E1=S;omo~x`)zUio{ zr$EB&TEON}!tH~&y<5TOt*@+H!sxEBt+2ALpSHV;x!GUE>anx0VaM!Z$nIpx@3ptI zYslzq$?2uN!EMUwZp-VczrLuz#c<8-qr=8>&hDkb=5)~Uea`TO(Cop(zlPE6!o<Oc z((b^;$gIrIiq!DM$Ha@(@y5u-kk#z2&(g=q#*x<T#mdc+*Y2><)Rfrov(wg=+VQm1 z*R|Eys@Lnz(9E{h+0W6=x7XUx($Bcq+rrn@r`_<<)X}Kk@w(gI)78?t+v~gB-@M)6 ztKsy$-r>aD;l<tJzTWQG+Sb3{@5bNbz~J%6;N-#K^2p)l#^UYC;^)WX?#kon$mH+O z<m1WZ@Xh7w-{IcS<>b-k<<aHw(&y&V=JMg>;M3^m)93Ws=jYVu_1oy_<mThm>Gs^| z>gDI;-RkSs>-XO4?BDF|;O*|=?(gdC>EH17@A2;O^YHZd^Y{7o`uzF)|NH*``~qhH zPXGV_0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_00Rd}L_t(Y$L*BaPZLoT z#&O?J6r$p;DDH~8qEXZl6<5H-4YlIFiyMf_bypH`m%5;WOI&KDg)~)+G`53GhY*HR zXIO`XSSW}nIe&q()Y=)^2NGj^;5?jpxxf3}@60*J%c~{+bzH>w@R;2p*zMT3xMb{Z zLc-Zc*we(s>u<2P_wJ{>$3CPzfB6Y>i^N7oM#f_&*G5HM!V>o#Jahv~jz4ue1xrgx zy80UXODemCH+#&Ivr2_R$$d~A%d&Msu0^%ZY)5vhm9`@ZqNuM|@Ca+MSXji8B<Y$N zWF-g_EkmlSJtKq_(I!(9q^jySLP`;aAP8DOEbbARixS=iP1hhBO>^q*kaWa{$1FuE zD+QHW7Zp3hFq{fa(>7$IC`zv4K-gX3n^yE+e0X(qc;6{gFYFB*dh<Zwq~qI<?Tk^A zGNhtHM0x`kk3+cB@FaBU7C13&IKY_EmtlOWC!`y|hC%a30n8ou4A#tOEDH$*i0JjD zv8zgsl$MHK`~dch4GRDWU$_}Q&v^ws&o}%y*BKrTc_;T$Tr5_s4gau=E&wy{OoX4_ z>mc~snJeFC!=lMeDkdU=N{IJJe}E%PA|S&z2tGpaJjepSTV%ORrKm{s(gPqG(E|aN zFL(j7Ms)lN(4jj(+4NMM+)H7hfG`69)+1V|*n^;zF}_D3!@o}!?BAx-5i+EpKt$%W zY8!y)9qn3oYCmD)HQh3weuKBJ8s-z0nwjYVsp0;$1+iRqHYY*g4A-1E!MH`5)nobj zP8AzsDazUW<=niK2qPd@$;%TEel93P>GgUNk$OE>B~r(`AT*kET!xs<4#a4n_`^J+ z({TuqDIn?To)C+{U?63PMnfRnGs04&TNhRw$E`9XH@Ddp6A_n1QI1N4`x)VWPDQ#d zxW$*9%`ZO}7lgzGu2!pzNHWGbT5S$D%6|~Cuo|34)HpJ!R8mB#Fl)7DQH8G(DHc}a zxL<8TMmfSUT*D|GUgR$LrDri3jk49}SmVv9SWEn0@e4;h=nHVhTAcs@002ovPDHLk FV1m**ONRge literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_gather_motion.png b/web/pgadmin/misc/static/explain/img/ex_gather_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_group.png b/web/pgadmin/misc/static/explain/img/ex_group.png new file mode 100644 index 0000000000000000000000000000000000000000..8d5de31bc129a9abcf4a73e19a48739139f66271 GIT binary patch literal 1228 zcmV;-1T*`IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=(EA5f2CVejTwfiWOA0Fgt11U#9qOVHuUhw@a(tm>9z9h#qH&> z?c}iR<FN7S!|>?B?BK2I-mL1~tMBB$bEG!w=AY@{n&{q`?&h=R*_GtekmAse>DsC4 z<DBHxlHtsY>Di~^&Wz~SrlQAS@94Ab;k>5IWyh*@@aDkh)THLqqwL+ecBwj^wTIx! ziQdJ9-ou35!Gh+|q2I`d<<Fq3)@|IrfaJ}di@s3r=D_ROwzcJZ<IJAp%bvUMgW9`& zd$dE9%UpG!OlO!lj)kjcYthWj@w~q5zQ66y&+^gH^1{OI!^Q8@)brKV^vKBY$;t7` z%kkOT_1@n1*Vpyo;rG0~?5C;bsH*3`zwW@o?yaxsud(UH#qY<+@3pq;x47%Lx$Mi# z@y^cjz`^d+)bz*4@RF6$yGLoX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0)t6JK~zY`?UZR(+CUVB(*d`NQfXa6^~z!}1Oy^sF^V-vQ6PniB6gWpu~n<K z*4lmj>zxTpNrZFE={Y_9;C#4z;o;8n<_!#Ueg5^if#~TvJ0ZwowOV^nZ(o1^02;Vy zu?(WYUYl(Q4Gr7vw@^pKIx;e1MSTv3<2Jf8Iy!1WJp{L*;juA`9sTu|@d=i7GIzB* zcbx`ea%zfYVA|z!O*g08?e>7jJHz>4miG$*&>@5fk}cqxo11erraKf0N5CtJA`kxg zXjIZ8>{QT6K3YgD<|aru>;+DY$NeBgqlu&uVVO20Mv+K3EONld<MRSY3yFkmKo;vr z%VLRIaMZ#t5Q{)kmQw~~SwrptJzZxz;S5eXn_Jw|;E6=MKJf88zXAbCN~R#CDCt$u z5zCqTb(dHyv_vdKafVpTQ;S3*D}%DOp38&oS{ZE#LxT<JgH2|$1qIUUxtyxol6lbB z@+Vln5v*J&tfe8J%N0vHeP`xj-Nh5}&d_Jg`!|S1QnN@Ci&a%El?{n)noX>UfRE$& zSy&MSDF7*1R><$?^J*E&rLBr_%XS^%;`MqgXclXlMUhx+RjbvC5!ul?)~H8Yuxhbb zEkWfnGVy48hc@|gu%#mXatCCbFywBqAxIKQNmeuqm0E03i*lu6bQyolvg{M)DW<3E zG`wPq%cPn3+4J4qJzU%0fAJC@93H(o#>acL+6g{6I5>Tc4doBgcOSnwJ9~SM-(6h1 z|A0S!`uyc9{&xO-zlMMOJUluzB3ffiAkFe$9ch*S>MpJF|I(7_Iy;r$L}JbIn@VhR z$7Es@G5cI-#kS2oefq~wwp=~2>+`>z-(ue+J2o$;LI3~&C3HntbYx+4WjbSWWnpw> z05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppn qF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTX@`Go)g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash.png b/web/pgadmin/misc/static/explain/img/ex_hash.png new file mode 100644 index 0000000000000000000000000000000000000000..9f35c76538c3a41920a7b93b94bdf97443df7aa7 GIT binary patch literal 1169 zcmV;C1aA9@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001n zsbo@(8Fi+|Hi*HY#9nXB?oYw#V#exs&h4h&@<F}n38~^Nv*by<=84npY=q5bYthWj z@xa0E#>el?&hp;g_M^vPyuIzKtmw0}>eSTprp#qVzv+I_?y1pfi`DRv*YI-8?0nAc zpxg0|)b5kj@2}wVOTX!?)@^0T>qEQdP`>AE$LX%xagvqMa+aa8;C8`}HuUky@a(s= z<azV%$M5K~?&h-b>%{Eiu<YTk?BK2N=fUgdp10_I@9DMZ-I(RolH}8n>fNlm?Sban zmF(iL<I#@k+^W3rgyPSQ>Ds94;H~fF!0zF_pG#z^7Z=B>b%2f~b#^4RQ$FKkW936b z-9bUQ>wu4ZIPc`Y=+~#`)}`#;yM|jA(>_1o$cW#@hUV0yu-$XX5E0BgJmJiW-o%9F z(xSc&4#hh=;K_*H!-U<zg67eo%w1jR)~4*;x#rQL<<Oz)+qdxO!sgSY<j$b#*|yug zf7-fz<IJAizk%e<p5x1&-i$@K00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0!T?jK~zY`?UU<U5<wWn@pV8EQt5^jN;fSkZ!Z^txZea>#3ciXMG^ue5lb*` zBLBL(BnC@M_{lzaKFl*S`~03W=gh1~bf??Z7>o&i8z-E`2MDn+LnITE(kU`Ph=my< zli!=3;UOHsGB<N!4<_g`tKc-t-v&Vskw|g>!NW(76$6NJ2r~EN>D;qx<f=ddDj?lC zzfvATB(nK=DOmtDJSQ(+N?*MuQ;UmBZ^#ftCYQ_Kk_phjJ0f{M{b7O3OfD}k^&$OP zSQlBxWkuL!wbR&Yce&O%`5J+BAl-Rq6m~(aPN&nN7W801!-mmlLX-KU#frjNP-nB* zbf^P6IMC>HI?ZTyx!j(ABM$Jw28;N7n`m*n{ee-CEij_l=W|)m<M#(C9G=C&reF~^ z#ik`>#q9t^g?o`5n$u2q89~HPuuHQD{TVq$evdr}9gW5IqV%<k!Qp^7d|{C&ZS{Bp z2@Eq#a=+Jwj-`OFxEFRI^_BMcgKP@sAf3+iBOq2Pl`555t<kJ}Ti5ID_PBQove_IR z2<Gz)Cew$9g+65OuP&+V_amCh=Zi_q93GcW`jBWYcl6^=7L(b`W$A2&nV)Qm)AC8> zY=p)*2{p#QmtU5UXB!g~#e{J`Q!Sk0S*=#954-)4+s{4^DqlQEV)eLGs$i|rXr2#4 zu8J*k#g<F0Rt+y2&1QQT(pzk$)oRr6yvav+SrQb(rKlFlofH>!thd|kzAU`IGSb`9 zXpM~`UY7p|xp@{|V|TiBT>>)4pzcQhBc}iW03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfr*~9W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a4e9369fa78c6fa19bf5c7814f8a586aed5565 GIT binary patch literal 1571 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 VFfhuORjdF2002ovPDHLkV1kgxQ(pi8 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..0051f996783873a4a27db4b971135e95cac8d744 GIT binary patch literal 1452 zcmY+CSx}P)6on&<ilC9wDWY}j1EW==VG&s^MyMc>VE_dIWsf2%OOQ>VP^3a>#ezbi zQ$WfpN-;oW2^b&=k^l*WB?JiB_w`TyKVY?Ov`?Km=bn3K?)P@ef&wq>vfO70gTZ$B z`}qW$(($7$%uVxaUUo4IW>yn~4)ryiwS?^8pZAsxthkhpJ|kUEnO0vS%3>*s%xPsS z2k<7yY&!WTdW3!iaT!ycQNDmlo}HT35l7XO3C;8jz~MlDOvDm~m7Oo7J-u?muxfr@ zpW4Z+8|Svr5=g76*J7xhadTK|9F-Zn1z?W=#EU?ha)Ykg7?VO|88jh>7B!m<YlhB+ z+ihIKOFme=tgB-K^{c?37$i!dE}kC8*Y^qZlX7DhJFTT%m|NeG{<NMuQHSGZ&NB!^ z;v%k3I!Km}R=5~+lUn8L%?)9nD0kB+*n|W|{W4?{z}f(LBJsvL7vc+yV)2Gr{Z1in zFoNuUS%J~8tXEIz)ik||2I-d8IN-v9etFrj#(`wAO|24dG_VI%MS2w#P*Oqdl0sB3 z7yho1^%ArX0Ocg0m;^P88U<b>@6$+o03~@7;%^vuMm@JJ<aWoNJuAayg^%p>Gmnsy zuG1*Xb4;BYgOU392vO(P&!Kp6@p=_SEyk&Y-2;lk%6vCay<jj&HE-0dOV0b0N7*Ii z>@A6~WuE;;C#7g56s?$SP%?QaR1+n-c`~kT8uNVa*2|@o?lo)=KN~N}8`2cd*w{>1 zTTgj<YDFZyg1O@D{UE}YyxV#N4ySl{7?kr`5m_T5X@ui?`P^!3EZxhC>gh@L@R+)G zO(PhQvf3nzE#>#mKw1u{SyOTb#j{N!#xvnegJKyEY1bgl8X%hmqzq8Kx;j$0LMUJl z<qK%_8X-v|7+3Q~)m)Q^fP}#wDqs)hYxrZTbs`|9t4#~%jZRFLv+$sL4Uo=)sui7h z#-L;~yHiyh($Tl5Qd2dzWCRC>z`VsQjOo~s>UR}uO21G3b~5>_sl;f1pL3yp6Y(*2 zTg|QPYVFdf4n2i1ryt-~R&&EyEH~GIaAZa|e{p<ldYm><(Ym$Sy#1kbWFdS!sl4#8 zg+-&46R)?p=v<IrxKAkB`h2<TL4-|Z@SI~R;xX*W)A-68l_8JKw;U~tw3<);5q%L& zO+WVhmV94&T?E^GFg?51+bpQUzhTmQhVhm~3Z0o+9h<ZCwR#@S#fJ;<<Zb)oT##J| z)~QSg4M#(dpu=3@PP3E!chc@*v$C?VU<{A|;Ea$C)Mvphc3Q&ID5^bSMg}7&YYEw! z+G=rs{cXF{PQvQnc;JJIsEn$r4gNJx`JpL<IafAY`AhBA`O0bGjYCz{Rlhy-wHk~D ztSrl;%8Mf2s{-cqz(t1-!B^mBiO9Ppot??{A(!2P0&-5fl5P>dx>DZULg*TK_Nrt5 z-2iOB@sKY=Jc0s3a*{6G2s_h?5P1!wrHzP^j*5=&P&pEke^pz|yOz9TpDUboGQjBx zMo!1otB@1eyV;Rc&(=*V+v==K^@N)awupf0xSm8APIR0a))g^~LD(V`iz%%B9lV<9 zNW9qx+^!S-`8sx=M=9LFn)pSWRENVZslD!B8wv}&N}w0~Q)Iq<_h*6eL%R>T<xbtB zHVKX_vJbiD$PIhPc3|ksSjnS-lh?8Q_gnrdZaWp#?-x#cg*}W&rboNyF#et@q1F6p z9T*>0alj*U0b~~`wx_Vx`_n~Y1o};*=weXmz#wPa!-WHU)K7MW;+k{KB^hrTOISzk zQem*}7uv?l*3EgQg4t*IhG!(iW+b}Drze^M=7@AaA{-nMNQY2Iq`R||yR-9g<Y{*# t(zVw9;QxR-DG5oKoc{o%+b7`Tw>#41KY&_u`GpC9`TGX?bfIFt{})E(L^%Ke literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png new file mode 100644 index 0000000000000000000000000000000000000000..76c546a4dadd7fdae310dafcec2ecdef9649d4c5 GIT binary patch literal 1377 zcmV-n1)lneP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006>P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZJydFPPaY zjqWG6vC4&kzm|uj!nL^a^ZV4*@~N!lj*;EL!|c+nY?{_9i1sFWzH5(?-O$nT?A*cg z?Z)orvhC!s?BcKR=fQ#6N$usa=Gm3y)|2GZkm}s3cd&fiz>e(VuH@B`<I<1f&W!2U zr|sXy;?RxZ&5Pj5iRaa&`u6Vc<G$$Fr{~tC?A^KS-n!+`q2$h=>)E#4zJS}je%iZz z<IA4fyMEfbeQRKz9{>OV0d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U00K`* zL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U6fJ!G0)j%qd?aZR z5fu}c7>rs-_lqPS2uKb<h(XgGuGEK33lp=Hw2Um1oV<df5)(cx$|@?VY7i|P>Kd9_ zOxilSdivP3!2P0PU|<N*L%<e9h$*WW0rh~yjKRJz!Ik=uLrmGoKm|mbnweWzTAAVs zOBC;`SVOd!+t}LKo8n3rs9GE#S{$96U0jLO;s(*;?&0a>jav({i+z0kltEhjT>}Dx zaQX!$jRpIKgaY-1nSww#aj8!^Gy>=})5xgkm{?PyQeSXrL>$l-)A)qMq-30aK}mc* zDRE%Gq^6~3Wa89<QYfipK|(A$CpRx2w-)50Po)5&rLZW!xCEzPP;Ds%YatL~kR)gf z39qtp6+&Uk08WDD=4PfK4Ju{j6{^H&F|VwwG&cpi3aCSkSS=P1TU3bB0n$=sQ*DYQ zQd3)3UtibI*wozI)Y6L8FP3fY?MPZWI=i}idV2f%Crq3;Y4Vh*m|7qK8ivp@ZTgHE zGiJ`3J!e`6kUM)8rXJI|^X4yD2)CuC6QpC&l-Udnb2@84dZu8w&2;gSrOTGXwbXV2 zb<9{X8N^;$3nC}CU}#yjdd=E(a4mJ+AT3RkK<xE(AaYU@hL*q$8#ir+YpL%6X=$Da zVsEJjkrSISv~1nBJ$na9TF^p_D2MG#-nDxVY2M$pci;X4qy_TsgNF_wv=9}Q2M(cV zAtJ$;mK->6poFAkiJr!&3jm~}-@X0I9(w=)03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfh#BXQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png new file mode 100644 index 0000000000000000000000000000000000000000..ba24ed16aeb0d93bd133902b0b2218e674f84528 GIT binary patch literal 1402 zcmV-=1%>*FP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006^P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YN)&~ znAt0h?kBgg%7uZymWQOmwYc*0`_$F)sjTIWk=?<=?9#1ln$|0b_9lA1YmbuM(9!Yi z+`;qh#_r~_?c}iR;;-=M!GYRI?d7rN*_GwiljPHo>fEY#uzcLWj_l&D<kgYm(vRZK zjOo~??cc`Y(2e2Ei{Q$M=hdb9_U`ZFzUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyHkc~n00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~ z0%b`=K~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4 zBxw;56%&^jj9OrRk(88VkYoTMLO_ZS1f)P}iPb`eEpWepZ2==#y2F+Fuz8<}Sz1O` zj!9lYQAwEzpB5EWRW)^p77h(fEo~+pT|IpRY+B&4uWD#$1kppl7I=sOZ7~Mw0g0J_ zePN0#^&zJ*6=OqH5N&2|VQFP;hAZ`<cwf~9qQ%12&fdWcSGqve;t0{=<m}?=Mx+*Z zh!zh|FK-{*T994r>*ucm(h}en7!-`tFNhEWf)M}EFrc1rGZ2VCmcb2F!XklAGmDCj ziH$QOD!+z=MaBbdF-u5HN>0J)7nH>3n;H-HOImtHW)@B@D20-0HYCJya`W;FaBD#> z`cw-cT8fGbN=kA11=W@^uoeO#21$Y@knk$6P$d+m4B#YaVPS3t(x6&iQK?3Z7K^H? zDho5PtAIMxiPd5Wu|<_A9Uv{$wl!u*BDHn(4Gr~;P0cMW&8=-%{bJSb(Sf9;v#YzO zx3{l<!o*3FCQq3<4O0swK*JF_rq7r;bLOnsbLLL(1ajxh#?)grZ~lUXi{Q4@c7b#( zo;rttVQyC~NY7LZx0x+jx@`FhxR$zZppKa<r-0b2>Oka_Rtznx*Q{N)9<HUn2c)HW zGKjsQ9z;%V#?TV9ant54a4ikJAT2GEK<upzAaYU*hL&yHcjW9ONefzt5#_L5DZBUV zCC&T0_w7G$khDPFbLjA4gchQr^59_<Ekq<3v(keH50;XYEYZ^#bpZet8{@o}32r3- z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f<D*lWB>pF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png new file mode 100644 index 0000000000000000000000000000000000000000..fb536b11b68fca6c2feda14a8011003678204d62 GIT binary patch literal 1389 zcmV-z1(N!SP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006~P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZLlAj_u#Z z`u6U(vC4OVr-z4&!nL^a^ZV4*@~N!lj*;EL!|c+nZ0y{@kCNSe%Uhb(E6~yL^X<m& z=CbYNu<YWm@aMsZ_9pG+vF6#8<<^tr(~#=is&%M_sJt)i;;!V?k>k>j;?9ie*r$Ha zR+!l<;?RxZ&5Pj5iRaa&h3hnp?kDf#zUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyg@M18hosTq4gLTC00DGTPE!Ct=GbNc000SaNLh0L002k;002k; zM#*bF0006~Nkl<ZNXKJfAR90;fdC^ZT9}wwSlQT_NYcW=$;Hh>nikS+;RXAJmlQ30 z`~reP!h9rY5fK#=ml%v%NcW2*9|%YeK!`!p9j?@eO$!sVl(dX2lbpPQq7oB6Ey^k? zs%j7|9O@dHT1?tHx_bK9w7~tMVqjnh(L=x%M2IP?7y<Qw#EikdFu|4jkV8z_$Up@| zo0^$hSX!Cl3QH94t5`#{nA_Oe*_+}@7pPhsAX*%qoLyXr)Zzxw;_l(;<&9elvWtCu z{ggpk{9OYAgK+u<C5;99g@gk2gqeasIB}^@IWz+3G}Fka=$KejqEcUQXha;)7Ss5I z#H3`LenClmJ}Gfvzoe$6XJq2kf>J1{WI;kKJ0~|UAGa3dqEDp&qNT7XzqkaaUr=o+ z1#2M?Vvr<g3<<BYauq^h$^cG+=H_OmAPp*I<rS*LXfdy>tTZ<Ty9%g7jaV%f5L;A; z(gD&^Wm9d6BvMmbS6^S((Ad=6+|<&F)i0K9?(IlgIy$?$dwP2N`X@}BIBD{fshC<I z0UCzTF>N}KoH}FXtZ5xU#_SoGdQ9icoi~30+?JY7kdD?VGZ!wL)ma15GX=wKri&IY zS-K3arM3%1wk%%=1S@Jm?8z+{T2`)Fy=E<3OI<gJY+47>vc3+)p45b)C2+&WO`G9b z>U%(B^A?bnt@R-G#AXaF+qUn>-bs=cv=Af8VY`xd@7YV5_jm8xf8Zc#fxPF?;ll_m zL`CJn!zfx{3FgRAoC(IX<lw=BB_t(F^fX3Y007N*+;lfqX*B=<03~!qSaf7zbY(hY za%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0 vW_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfuI2JN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0018157f64a5ae601a2db08fb1e4a553385c33b9 GIT binary patch literal 1417 zcmV;41$O$0P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700072P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YTUq% z?cc`w_U^Z_%6EXLhlh*8wYc*0`_$F)sjTIWk=?<=?9#1l?A*bRlHGmFTbkA@(9!Yp z?Z)orvhC!s?BcKR=fQ~fChg_1=Gm3y)|2GZkm}s3b*P4@yf5tHuH@B`<I<1f&W!2U zr+&{?nAt1h(2e2Ei{Q$M=hdZ!>okq-C-39F=-8*{)}`#-x$NG$<<Ozz&Y$bqw%ope z+q{0-yM5!!p4z*9+PZy(fxniAqyuE0`2YX_0d!JMQvg8b*k%9#010qNS#tmY07w7; z07w8v$!k6U00L`CL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U z6fJ!G0)j%qd?aZR5fu}c7>rtAevy=vWRPS4Awock4+Nw@YKhfChAnWvfNcRISh~ZN z`mlMQiCJ1kR*p$tK~YJW37-}fRaG^0h!zeFO)YIE9bG+r18iF0v9D@qXavziz!rFj z0c|k`>H&$FfPG<#EA=6#F%@G&RS<1vZeeL<ZH6oLp?F`_2BO8n*3RC+3|G29)#3=z z;^ge&>PDm%cZe1bPcLsD+**)b?Ca;R0@4!T78n$a(=Uh+1A-9$&@iB$a5E5yK$gJ` zRKg;GPBV*&j){#kBPzd!ghj>!Z81woOiE6{=@*p5=bIW2_DfoNMrIaHEhvSOYBnUq za&q(X3vg>eF8WjpAzF%x3rb3H`UTaNGO!i`AqGi;CXnzduTUivrVQXDXklS)2GXEf zUQww=j24TkswxXJu&aPN)QQz%39&_$C><az)wVTeNFud$^$iX6jZMuhEzPZMSp8zv z?$LpyrL(KMr?<DSf5OB`lO|7@It^0`BtXLvI;PJ6lGA3+nmxS}$e1$|Q;*r)dGi-6 zgxgZv1=7(rb=IOqv%6|RdZuEy&1~_KrOTGXwbXTk$kr8$fM8`Eh&`nhL(8hwYu2uV zYpL%6k<IHtS~k>!*pr(vv;=M3w0R3$OG7V+Y}pFZvaJEcp45V&W&4huIlD;Gf)-*# zIc#^zp1u39dcPZ&_xJ2SaPSamfxP$dks}B#L`CJHBPd#63FhcAoC(IP^w6P0r6eUw z^fX3Y000U{;7!~3Lt6j<03~!qSaf7zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4Fh zG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bN XH99ab%9mBF00000NkvXXu0mjfCZzUl literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..3a78fa6a1d35d8b2666ee3ffa5583db9662a67e4 GIT binary patch literal 1490 zcmV;@1ugoCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70007fP)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j_U_>5)wA5djnuJo)yKTSzu&2=<&>D;#mDaG==ksIwesx6?A^lL!H?z8tMcd6 z`}p$9v%Rr~oVtpQ(zUVm_Wa-A^}oUFs;%YG((&EGk@4lw_t?(XP%76v4Bcit{POSI z-Sn%j=JV~w?&h-X<go1Gukh!=<GQ)mQY+$cP1;Eu-)lwf<+0}3mF3ox<kOJq+^Wd6 z(8ivy+*T~?;;!V?k>k>j;?9ie*r(rPJ=a7P;?RxZ&5Pj5iRaa&@3EfMdPDEyzUbJe z=hmg{-MRG3zUrWd?4*wR<=^byy5-QJ<j$Y#*|yxifZM!&+Pi(@%bwc1e%iWy%Ued< zo^8}&Lerv`vZEDM00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~0*y&T zK~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4Bxw;5 z6%&^jj9N(dizFWiNDe@VLDL<s)Q3$A6SI`Gj4YF!yn><<6Fx1<Dk`dK5G@?)8k$;6 z+B&*=`q;F<{i0%EU<lDez!pS^DXSO(^?<~T!M-rTmHLoFOxegl1w@;gnOj&|nc@md z6z{88L$sLN*xK2f;z}2&S{xu+9G#q9T#3};2GQc~;pyd#TMM#_eSH0tL0bG>0|J9^ z`UNG81^b1B0`-KMf<QQNsZTjH0_Zf;$f)R;SW}`>UvOwd9MBfi_=LoyWSo9MNqjyj zabUlsrln_O;?#mtD5+#YLM%HcH!mNz7UZH&r2wL(uqeN{1gBq6Z7Bt7ArNAaBxno? zud;F#LSf1PPJ-s<W~LwwDrMyrs>En9udJ*zHwC*2s6&ldEfx@4REW|6(o$tpZHgpP zQ(ISGU)Rvs)ZE<E(u&nDmTm6sNLo5NySjUNdi(k(Oq@7r@|3BVS|9-$hR`u>Is?Ou znX`ak_8bO=x$`jfn9g6YaM5D8Ej67$9SlomEnT*J)~ppk=G-Y5ZZloEYW146a4of6 zAadP$28KBsX3YYzC%0f|*|=%*maT9tb=@GcX%djwHfuYGJ*f#pOW=;3yLQ91)c1hM z=7|gpduGkr3t~@f#?Z2F|AFj-7+MZ(n>FijJ$5Z<AqI2Uky*2jcGux>*s<i}Cr+Yy zzhyE|3qw~e4(}g7b^6R%v_Nj1GM9m2dS?xeKt6Hq{CR{HNK`URy)bLm#SR7>QF-<} ziWX>sxio9mWn2lywB+pBvn3=YOY}5GT>t<le%ij3CAg3P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f^-`z-2eap literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7764b74f5e5e5af1a205b2ecee9ed184727e1fe0 GIT binary patch literal 498 zcmV<O0S*3%P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70001NP)t-s|NsAV zbaXa|!Dg1x!H+h2o~cd1>4~}9VaDrk&F*&1?7h9crNQLey@{>X>89TD^V}-D-R=M0 zDZt<E!r<=3;qS-e@W|uv%H#0M<nj6DU(Mz6|K?xO=kn9&^VI3|*6H>3>xcgAhT-q` z!N@d;00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0Ut?3K~zY`?bO>2 zf-npQ;7O;V0?Nb_&J(=<J35L^UDqjzCdSySWyu#<`)@-0>*s42VGTQwXf%l9@iclL zNdOXeuiySypCM4!;O@y&X{wSOIUXq~XQs-}6QvYS4hKrA@L4=0l~^f9_IpA^Zz9B` z$BhkkJMf8s@sL*VhLWpb4Q#i-2+rIQ+9-eP?noQ0lYBNH*ld8!i7ZVDly=E_-I=Ub z0iwNRxdislWu;A#vn&>!J9Z<@Ox#J(okv2`=*=e-1+Z!K=krEr8ku~;d=B=YX>j2X z3`^5Z>~y=h^w%!z!<XmH<A-BxricT_g}zMDF0MB}&$8Uyetc9c(E*Y`k!1ybMZHLj oF&RsOM{v$!pYbjo``5SC8S!5pi4Z+;&j0`b07*qoM6N<$g5#I=_5c6? literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..d44eff429fa9a3409776ea88a11421582f6f4598 GIT binary patch literal 1298 zcmV+t1?~EYP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001q zx!X2~!Eep(M7`;C&hL59?^VL-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUOPl=ya2odY-AJ!Q^I^(ZP>4@#=@|<6!gf$nfm8 z@9DMj?Zxiqv+?W1?BlTT>B8af_vhLx>g1j3<DBW>n(yed=-!#<+?Va;vF6#7<<^tz z;H}o__3YxW=GvC*;jZM>lI!2C?dG!U-mLKEz|`sV%c5A@y@~4Gs_*2!)9CZ$)RE)T zkK)jc>DsB$=kny!kmAma@8e(T+p6Kris{*?_Uni3;k?b|^7G_h=+~#{*QV{@yYAa6 z^V}-n$%)^{h~LMD=G3Ii<nj6DU*5)s%H#0o)urasqsZg%{_KYD<-qLSy2s=2#o_P& z=3ngIy5`cN=Fy_&(V^_zxc}ZM-o%96!-L$xg5}Vm+`fRq;O^wkpX=JUz~AoV&7SJn zw!Gc#+Pi+^%$}{*>Ep|u5BdaA00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0?A24K~zY`?UdPD5>Xh3ZKAN;Q_C#*KwubLStTT}1_fLIkws7h8A(MzWmN>> zU-!(C!g1n>o1QNGE)F-m&yV-_9Zp~0%lzwkMX>Y7Qw$+qOC*vv#9OIU+E4Vqdp|Hp z3=Rzsj}RlHV`Co(QA9F6K0ZNAOioUIBtA_|O$`u3pQX}aVsv_XV2tRNGV%8*U%21Q zpI@J!9p9ai$!5?8$Q25O9A=eD<t)sqR4O&7Ns`onhN37fbRe?1IT?#6=I7@Xpj=p3 zRDo(~X=xcqonCJM%4js1F=S<>16kw|9SNjfucyFbG<8Q*i!8FN(;>v5|7N7XYFb^j zi6er`Z;S7og+&Wmv(4_nkhL`y`2p<k=g;S-7$T&omq}6$8iRq-fYxd@JHSEHv=d8N zUvG1Hvaqlg8+M>wZnp<RHaFW4Qm5mKHCn;Ey0JwA?RIZ>L3V^<DXv)CmdizhcYE9C z7f0lZot<3~3#Z5L4`9gNUeAs32*`uMAWESuRxLPecC-tp*W+<QAQTEmL{lKRzaI@^ z7CvMViX9xrG34k-K%&tED%OOq2kmmXz2Ncrd?5%Q942w(_?SncEW#FR7mD@!VzDr! zlF1~4AtxssvYSXG(yRsji?awIi*PCekvPMgV#wK9&yAg*b1CUWCX;4&;YGXf`$GYU zq~h@lIL+qrmmrE{uCA^!xWzRCxk9m6>W1*wBNU4rq#&NWE@UBJES7PkQfWgTi$%L& zt_y`cl#1nYRUAoYSeFiqTrPhDH>GOz219Oddv1(Jgp@!yg?4elFxgYMER{+qrCO`q zwWpwmuU=;#Kf#5+9!!C=D6<x|Mx$}xj>y*P&1N0_`voL*$X<^uSL_qg>P)FLo0X@O zINC)Pazz%YmdlMA+~Wvh&>fq3bh%)%n8jVI)w=6!OnAn7Y3ybGuXzBr6b33x=w6}# z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f@j>KSpWb4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_insert.png b/web/pgadmin/misc/static/explain/img/ex_insert.png new file mode 100644 index 0000000000000000000000000000000000000000..862d837277c99e17d2b66232de79fce010752e7c GIT binary patch literal 1065 zcmV+^1lIeBP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003yP)t-sBmgK| zTU$1W!3nA2a+aZzl9IuXHmaF8ou4@}wdHlD$3eX4%c58k;}QztMoPfx$EtN*#Oh<l z>TAd7XvplT#d&Va>__Y%vc!A9!GLwm?AyJ6+r5e0zJT1nfP2yJ+`)o`(eB;DgM`!Y z-o%97#f9F+hK$ti-^YjF$cT~E?%>IZ;mnGc+417ejN;IZ<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp;FQ>)N;I-kIv%s_fjj>EN2{-mL81y6fMq?B2TU;H~Q8obBJc?BTBM;JfPNo$TVT z?cu!a<FM`JvG3%*?dG!X=CkkR!0_h4@94Ad>9z3a!tm+B@a(qn>%{Wy#q;gP^YF+M z!Lnrl0004WQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkQhe<?1R7l6|m0NSt zP!vXK&`lBB2CJaOTA)a|q(Gri2tkO1TjWv@3IQV^xBmZM;7QKm5)32GIHM2U59@)+ zO7{1iGlRkKH2+{;P|ED2o<i9y7RwoRabmSzQkSo7wrlG8!sWW5Zmt4>Pn51=F&d2) z>IBhBy)v84HtG!NF6!#^)E1!r(pR3TJMW~P0*}+_^l{1Ycsz%>EXy;PNs=@H{0soS zsZ1XpT4Ta-wOSp4TqzX#AZ4@ZCSYUngQhh~OI2D}smLG~3Iz$e+4NHRx>yYJuvW$` z^<kBxN(CwX!so06?Q|;DAWA+@Hy5zZqVB&+@l8$9oxr5os0~RL2mO(muAG;k%==v= z?{&03tR0w-WO+_F>-VJ@Oxn%n5Qd^C4wf(0IAs5IimsC4t_ET>94@Z+-*8Z+6;vrE zDmL4OX6o)%1Th>A6*p>99W@-O6jM@*ZQMqqB9uZQMgW7>p*i#m+5guRgQ6hxVDr$y zp&Tmg*VxiQ7K(#Tq1&Di4jVOe7K2i;IDj6{=Q^OhkHF`j9~j8~+7t{*!3X_54z}(v zzyVU)=`^|+m|`><E<urD7#?zdpLbg!qEcy%5Em;j!C($DUayzcSJ3|AcS0pa52eUu zI?&-*wyvxEL1XK$h+=6#I1mKB2b~PZ-9tT@h=0*v4DY{{!oxzs?R3WU6?`!;`C!nW z0nY1jCn4^1p6^g_rK@7mS+E|rI}S1D`FTWN!TW1cBogs5lw*-d`L~U|Gby8??pJ!b z3_1msrXytzkCh?RRq(}7X*#mo?MOj9Ce&3jKILMl+*jeyDI_uXRqokjvW~fDmd(cA j94hm6lTUy1|Lgn&xg@`Em^A9100000NkvXXu0mjfS$;eB literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_join.png b/web/pgadmin/misc/static/explain/img/ex_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c391233c449bdc5a0d52d50f522bd3e35c649c36 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_7<@W^2*R&GEgz?Z3h8!ou#;)brTc^v=)n(b4kM)b!xs_i~n@ zTZg#3z3iu{=c=sduCM9E#_!9_@xH(9#m4Z~*7U)THuUky@a(t1!S2S#@6FEg-rn}> z=AWyq=(DuyyuIzz)bo;+(T1sHQjHmZrCYPXrlG`Mg|bG+s&$Tqt8$|?qQ_wH?6#)N zW$Wdh>g1j8>9p_bw(sb(^6bTgsA6`iJD#<NuG(>Uu0Heb#_r~_?d7rT;;-=M!L{Ui z=GvC!*OTPakm}s3d$U61)sf@UkK)gb>DZ@@!Bgwrtm4p);mwQS%8BRHr0(Lq=+~y~ z-MP8zf4c61<<X(!&Y$Yow(R4uyzqqFzJS}je%iWy<IA4v<DBW?o0iO7=--*_;H~M} zsqpE-@8-bX#f9C$g5=GfwL|Xa00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0r^QpK~zY`?UUJC(?Ar(V^BbpRmDM2l-2b%E>$$61+gq;DJ?Apx>_)8HEF30 z1qv<yI!QY65i<h=Jn+JOn3sINdveZqt{_~`MdpTR4te<yvEk;e#wM}(cFUc+BHuEx zwXMCQQ|!8T|3SCNw~VdAT=visCNG}~>Uq@L_ZU6tfBI|y*^ohN&5&~$8Xg&a{sO&x z)%W_19RZglNiNj$_TBprh!c_AZnuPnKYkkfd})N~g^7GY=8#tqWQ@OlJIjk*1$#W> zgqZ+yzW-as^djR)gE?nn@}vi!H!=L<1mfjN3{M>+(=)SYCw3BX`FwNp6fe$M7+;i6 zP0Ts|#ifABKyWz}Ug1&^<UqvyH3+S)tw$+doagEfL}HdoIG#wRD2Vfr7JgcU0O^g* zUkVLzoGXry#4@R@lB0NWs^H)F^p4ffmArN24^hdfs+Omy80GW&f-oN{gjc}IE4D=t zwfMKBQ@nt8X1hFR1{zO;+2q*P4r#JhD$x<&c6oOh3TyF16wJRei2A*N&O&C(yQ>A* zTTdh_V86<|uIp4UMlA~aa1gDeGGHqKGqL&y^4bu#%6@n+eE^xPqU7u<Y%fNWHY$*+ zR%<FRl1?Nyv!GOKHH{aECXMoeS}PV0|3jEwtnxul(+=~OPV9QFW{v><WVgBso0Wk8 z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f?exDGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_limit.png b/web/pgadmin/misc/static/explain/img/ex_limit.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3efd59d70436349e5413f8c5d2673200cd74f0 GIT binary patch literal 1237 zcmV;`1S<Q9P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(M7`;C&hL59?^MF-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUNiI=UKt$YscuhV`Hfo7w~d&?QwDGaB$~uaOH1r z;cjl-ZEe|XY}0FNhN)yyjTym@HuUkx@a(tm>$dan$M5O1^X<m+?8WZpv+d@x?d7rY z>%{Ehuk7Kj?BK2N=)$7LVC&_c>f@a6>b2?Mn&;e?=i8R-<FMt|ljYTt>))-W%w_1_ zndaG*<kXSm(~#=js_*Et=-rs+*p%bakE+va@8-bo<iD=jaL1~3vEFs<<gn}Btm)gT z>Ds97;k~rudA8?#xaxo6&Wz#Ai|N>>x$A)A(2n5BiRjm+=hmj@)urv<yUl57?A^NN z(xc|lqU_wb-^hpG#)jt9q}{@U-NAz8(4pSMh1|e_-NS_2zJTP;pYP?s>)N;G)1&6m zq2$e;<IJAw*|yrdedEiX37wJX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*pySK~zY`?UU_O5>XV!X``@E)R3}Nf|O*B$m)u`ByS4@xQIz9FPadbCWy#_ z5QxIR-d(t0;9^epp=NwO+}WKuzd83g&$%MegZ^zjB6tlvg%IMgSS)@*Je5c!L&VUt z=h9(fctj=}B}T`_$6pYFh*&O{i-`$^Lh+J#H90vcB}QJqnUWD>)6>#%;<hdmlBqj% znNi+NGuMdnZJ$&sm0G1%znh(%otvA}Xf*GU=I537>Y^pJA`vX;bh-upT-1Y}qNpWU zrdJHBuxd1!Er6>!B0rD_(XFkm>CkDl+JLg#?KIF1r;`Dr%kB06uIeHmuaQNo)k-16 z>!rcq^!bcncKg>^z*Rzst%U@<-VFmVK3~uTX8-!;P2>~V_R@9{;9VHHF1A>f4FRs| zBA?OE7vMGU#8sVnk=rDx1^uFp(!)}Krk7!LhhZ#WF?+&W5Q;>jF~C)w9^1QnUrFAD zodO!W2)fMJMPxr7PXMm!blKhehPqHzyFCE(hQql7Owi>vLwGZpj6gIVPo)7@b#KOh z^I4$5t~i`N223uuKMZVge?JO|R4R1<xT-gO?1Jfc5lbH&9`&dHC!2h8X_3C)(ET>K zCEkTm$i;CclRW{Uhm5oEtZyb+ez5U09OO<<^N=|!6gXkT=yIVYXK@xOl*Qp`v6z8u zp;Q`xnA|;C<PITUES_h9E0xL>VZ`DIvp*md{nbSlxu|lLN>vc~?IsI!LGL0Gf><J* zK7ylszIF^J7aUiGYNdX8C48}77w26U^+u!76h_)hp3ddaU~A`Rg$v-yWrSP~M%qh` zvMAR0EYM&p<#MBb8`9%~Yq_ZNF0Pu*=GEVt*n|Fa{RGa817HRj*Pj3Y03~!qSaf7z zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6W zZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjf-+GHC literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_lock_rows.png b/web/pgadmin/misc/static/explain/img/ex_lock_rows.png new file mode 100644 index 0000000000000000000000000000000000000000..41c1148bb185c87898b3fddaa76be36a15703336 GIT binary patch literal 1520 zcmV<M1rPd(P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700078P)t-s1prKL zYin<9ZE<dHb#ijIWKo23T)1UXxMxwgX;FK4c)Ds)x@%E3h{3vUQGR@Ux^Yo}etx`j zQG<Yhyme89f`YwxQHX|yzI;)Nh={*{QH+X;38~`0f>Di(jE;<qz=Tnbj*fDcp^%S{ zz=%=8h*6S~l9Q8@!H+hYm3+dEQI(aIm6n#4mzS5An8cD%#F$YswdI<go|~SYb*9Ih zp`pT_QO2H8o};6lq@>5AQ9-=u%c5Axr%}nMQA)t+%BxY=s7}hQQOB=S%&$?Wv9Zju zQmC`DUBv4BtpTdFwW_wZW5(*uwpDA#=xE67&bnBwy1LG~S+BgjZp-YjzP@$M?Ap72 zw8FyMy@}(!bKJgw|GhAK(eJjz#N5GxgwgKZ!-Is=@ZQ9P-o}QE)b8KMhu_GEk=5?t z$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+m zlIGK+<<^tt)THOtrLN%f=Gm0!*QV&#r{>z0>Dj2~+?VOvsp{Fb>D#L7+PCQ5nd;rD z?A*BN;F{~+tn%Ha?A^NS->vfAr|jOk^xmoL;H~Q8ob=zR?BTBM;JfPNo$TVT?cu!i z;i~N8u=L}t?d7rb<gf4KzU}6+?&h=a<-qpkvhe1>`Q@?i=(G0cv-an-@9DMq=d<wX z!uaU6@a(qs>bm&qxbf@6{pz;(?7H&p#rf^N`R>2@?#1))$p7!Z`SHN{@xlA?!~gNV z|MAlO^v(bC)c^F+|MtiK_R0VD+W+?3|M<<SyU{8D0004WQchC<K<3zH00009a7bBm z000XU000XU0RWnu7ytkRE=fc|R7l6|lj&CyQ5eRxeH+_N%WSus*<!m=*`Bu8B8iHI zC~mlcpojwm1gMN_hN04AG^HkyMp;_fzWiC;xpx#ij-Jk`bLxZdhi7KancsQe=eh3< z3Yw{ZPzMOMrc^$J5DEl>R3a-OF)@e8xgr!66UABC*%d@ZUSZ)af)^1)L_`RP1gMF` zrP$b5A(0C4Y$7i?Sy)K?L6_Y-qqanb<M+*I<|&mUcAZbVnRe~SO7sCn1_lO3#?<5S z41pnrVSK<x)3g_0A|~ZR%)0Q%xVS|K8R+b6_i*ZIY;5cUjNNMO2DH(rb8yJniyPR- z(tX=Gq#Ysc7_l>ev0AM(=rZcYkf@Xxj4t0ln?*eB=x3yTb~{A6t+$OdaO!GmS~0Te z24{TE!C>SC%|Gtq5pvPx1ztyMQx8I}?^v_?^qCXK;t$OVo);YybP}+Yfi!)xvdGo< zqo2Nf{PF$s@L+%cR@fzzEilx_FhjuC-A(&|*XeNdfF6pX+^Eatcca5>4G#A9K3UHq zNl8hW0WP{&7u8LGQYjQRgq(YWkWm(S7&eYDb~_H%=md_M>PiYw3PmYKPQCUc4?_J2 z3YJE}wpOZC6sRjLm0J*U{FNWMzhd0WWEXCm#o|Ip{0l#FH{`bxJN%qQMiFvnG3?@_ zyPRH5ds>^|S-9(LHaBpY&8802W$)8xFF$<!`R#4*z2@cx5W(|LbRmZ>%tZzHdW7tW z-nMaVSm>%{Axjp{p9>MEP6rnQE2UB?>VQoymz#m9AYY~jd{+!b+Qcai)*>$|G6923 zCL{R~I6w86Q`UtGx-c0!K!=_rTX>P90f}WyPLIC}Mb){v)4|$d(Cgbki&j(Bz&{wC zAMXHG=pvT{8mUC0=11^i1R{D_u2c)EBogry2#z!mA#<hDDxj8##Y%p}ZLyeL6TGx& zG*$JWUaeHt|Fy(iCIdVLtZgKzZ2=8xwHkI&mY3J^4~7>5D=9@T#H@>Qkw{d=j~MdV z#lWgX!TOOBenbyXLCdK|!XiqsSX2(mrbgOGEu0@~po`j)l9JkK5=)=%R?gJ_Sib;} WuicyymX%Qe0000<MNUMnLSTYGrAb2o literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_materialize.png b/web/pgadmin/misc/static/explain/img/ex_materialize.png new file mode 100644 index 0000000000000000000000000000000000000000..c3bd0bb90dd2ef1cc1baf7f932817d1b6bdf463b GIT binary patch literal 1221 zcmV;$1UmbPP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001^ zyUc^E$aSX2Hi*HV&EAa1-IK}Ps?y-H)ZnGh-mTK#zS!b$%<V(H=}o`rQ^M+n)bNzp z@OsYdhtuw@-}7s{*>k?y5Ub*3#pqna>5|p&pRKHao1$`-p~$a;;^52R-owF<HuUhw z@a(tV+qd1?w&2~u>*k;8<eu;8wd&)Y-PyJ2;hXR1v*6sp^6kaUy`#sfb>G{;;oZva z=CbkX#N5}k+|{$*+Q8@Bm*&}&?BlTA*tOf#vFYHN=--*_;H}=+zU0-B;M>TCsbo@( z8Sv)7tJG}W*1h1`$FJLRv*CB}=)&sVtLfaT?&7`L(XZLhuG!A5qQzgO%Ve<JbGPSw zxa)u8(U0QJjOp2^+S0Jx)VsRuf#J-G=+~#%%&gqgy5P!*=hmj**v0JKy4%va+tIk@ z)THLqqu0r)-^hpF#f9C$g67eo*vzZg%d6JMsM^oB<j$bnzJT7<!|U0$+RnGy&9~&u zp5x4(<IA4a#irW2ecQc%&=gc%00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0(?nCK~zY`?b6p*8bK5XU_ww#jGAI1rVXt0A|?yUN>Pg78bgs7LkqpPC|yAQ z^~}hc;|y@}z&Sa2@IKs^*>CRt?k<n_Q2(eN@lkOdJ9#WX#r69K{Ds9u;S&GJ)1~ES ze2fTIR@a`t5WIY~zW!Q(k;OL~8$t+$3(Evq6^TTff|a$mo9_g3PI><U71uHH@iqn5 z?;ilML?RJ$9V671R4U!#Iz}WinM{JZTtN`2QmK@pu2N4Wa``NxQfX!ot#$^{Xmr~+ z;j$<c`Wac&>g^qjd;+Mrj*-t4Dy|b#6bd*+Pt%5pDQfi=wPQ3IcZn=8g&xp*CKE$u z(db|b<Nm(cf)j<-YNY{fGTBI?)*T!gAu*fn1hHE8Xuz0kHU~)#4k59a%}#=dX_Ugi zI2^7!a^yZjWSnBxZnt~>x-s`LGP5^kU>L>)TrA6;0C@jxeL01O+O=3LUn!5*>+|C; z#@J8_HgFbX0nh#I{QUU%`{~6GH;+r<4TZxIl0>5{V9$cV*q<pEKhYGs)9Lh5zHmIA zz=<Oo2tX1{CR2Cu-AEu33i+r=Je|(qWSk-!OQo{J#ynmhOyN&tGP$|`u@jb!WkEKd zFJy^N>4`)VekxZimGCKCihQ|TE)WE!sAQ;OwN|U+B$oVjnFob(`Km#XM7mNfQuSJ` z*2GEb@)F)(xVoAknM$=<f~3_V2ujfg?M9=~CJ0PX&rzLbv)P$@W7$Fh-rw$adlOUY zb$Ea0x<A0Da4EXO;jl-LdJCoK-`v~`aMFOJ3wl#Xvo#uBQ-i4lK0K9-M)2V&WSpYi z>rG_o^ihh=U@(|_V-NMe)o+jt(ePu5AK?H103~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfVJ3t* literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge.png b/web/pgadmin/misc/static/explain/img/ex_merge.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd8299fdcb72604d0c97816d38ee25ec51699ff GIT binary patch literal 1127 zcmV-t1ep7YP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001z zmC<Hv(ap~CyuIwd!0pk|^3&Aw$H?!;$neU_@!Q+=*4Opn;rFJf=Bcaa!NTsv#qYJY z>$$q@!^H2!#_)!zWKxY8p~PNwrpGpj!Eep(LA>Zn!0CI@?}XFvW5()e$n0**?3dZ` zpxg0;(e8}Y?vd5*uHf?tsp4J4>N2(Eb<ON+$LOQSVRDwC!H+ic@W}A&w(se*^X<m& z=CbYOvGMD~>g1j2;F{;$m*?A-?BlSe%w_81oao+}=Gm3(;;-o4nC97(<=2z!;H{?6 zXYAmv@aV$Fs&%W?Z0p~x>fEaD<-p_8kK@pe>DsAbl`meHCBewL<kgaJokg0;U3jiO zp0$U%?SbUekm1dYi>qviyiJ|ZV|uVayzqqY<iF|Ir|#mtzsI+$-f_6=fAHqO=+~#` z)}`&=yWz}=;K+#I$A{+Bq~67a=F_9#$%)>?h26u0=Fy_;-MZ$|qU_wb=Fy?$&!Owu zx7@#g+r59}&Y<1Fg5%7dI?;o_00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0v<_3K~zY`?bGX5(r_3DaGDn~EzQc+f-=ht?ef4F_ZT1uwF%R(Lb^=WWfKN0 zFq@$K>;1-ob697`-_$p~@OkmP`<&<Z{qD@+xE#k7!Wh%W5n^n7Vq%hTUY)u&O-wtT zGuH_$8NV?*J4f7{pT9LmOy0gTHS@oavu8O+V;7hOa^b9myh~n)+@p*!Z5*NQyWH*v z)WgL`OOL51%THIHQCQ;gcsy=ub#2Y{oLXL8e6fNj_O84fA+P%HH*FjNug~Z6f|sUg zKlm9Y5Ckmog+d`3=x{j9027HuW0vIgKO}AtmSrFiO(c>wNIZ@R!?LLW#1iZ2j3wDH zWf`OhpcKJmHj~4WH(-ouTamY;SNt@?_#qgJC3BGDIDQkbgke(=lwv)NQgHcvL9ilQ z8{6+3!+!vnR0I{9Os9(+@P&dk*?IrrBQj*kFsRrlDmGgz?(&F~%a-KR=PzHkNs=sy z$c&`egFQj0NLJ(<GT(ocN}?!|HXB1`XA4~s`&V+=4EGZ@c|njsl4WJz>dLS<v7aT= zPa%}c)e6WpRjr>w290sM`GP^JRT&hu(P*AR2H%Cx8^sD$O;e!W_|<CT$uNb2QXDjY zw-2$zW@Dx+l2DN)*ss@{2XOdD*N^ZIt7uwnm_qM#y2p4TYc*7Cv(-A$5$Se&c%rB( zDz@D^>F99WwM7OgbR)%4uh+w8IY(ocV>y2TWnrZACmaDB0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1n&OPyYY_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9aa51fce9d775f169f70d115761e9817541c48 GIT binary patch literal 1599 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_append.png b/web/pgadmin/misc/static/explain/img/ex_merge_append.png new file mode 100644 index 0000000000000000000000000000000000000000..12fc55d76f504140935d5fa422f9a5075431bbc3 GIT binary patch literal 980 zcmV;_11tQAP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005JP)t-s00000 z003rd(Nc{WHi*FosNxW-;$)T3a-%gGuH(UvHg>8zdY-9xu0FMyetNM%gs???v_por zNkF{mMZW2fwrozm=1joprKsemspnI|>RQ3)jlolwyLFkoc&e=DiMiWd#p`6n=&rBn zp~POI$6%JsU2)6oq{?G&&F-hoW_r%-+rEF>y@|ZN?A*VB+`xgozwN%i?cKqGgVF8X z!h^rT?cT(M!ou!_)bQTLg~G${i`4Gl$A*&C@5RRNy3wP>#_+D%ag^Bb;mnHS&yCB> z@#M{(<j$YW&GF^VpySbw<<Fqw(vQy1^0ec5<kOJl(V^tjk>=8)<kgbV(emchr03M6 zw3*OTYfrLEud)710S)b!}rrs&tF=Gv9%*r(Rk^ttPQ>Dj2~+?VOvsp{Fb*xB^D z?t<yus_NXT=--*^+qmiAn!NCY>)x#C;hXH;y6fMq?B2TS;+*W@t?c2h>g1i+<;(2i zukGQy?BlQO<FM`Hu;AeL?&7`e<gxDKzU}3)?&h-Z<-hOd!0+g@@9DJg=)v&l!td&~ z@9Vbl>cjBtw(#t?^6bU)?Z)%($Mo^Z1Vq=200001bW%=J06^y0W&i*H32;bRa{vGf z6951U69E94oEQKA0kKI$K~zY`?UPkg!$1^;v)KUULUEU1#ogWAouV!7?ykih{xC_% z08P8uzzo9+=i$EWd~@#Ev&%65`jNspQS#J=aPdC=LHS%|Vph=rrxEdXaCDB~V*P?6 zOSoTiagtKVQ(H*3K0T*!kezPn9y(&R*|RBuD5{jL$;c}oWwnJQBj0x+hE!(ZG4|b2 z56J|uqU6ai*kJH@XNdN;E;@msASoyeeLdlI2K-Hg!O>Vfiyb6RLfk-<JSpwt1POuH z$A{Y&cse`Wy#}=#6BO#@!i&hmHd?uav*Et3WuQFNGM5Uyz`)%Gnzz7yUq|yS4PkhF ztFRheEux77*lcU89;dqKTir#MXUoaK4P4Akj_d*D?}vtngvyQCK3LpK>BaV2;4y5! zFcp^>3gRlIkf(HCo=X%&Q8JG`mtuU?vnWc&GXk+=|5<z>)+K-bO1R(MTt0_mbAQjO zbuYw{VGA{*NiY=`WVb62QpvD}s*xFtx!GwA)=08cuRN`gIaG!Ep))fzsaD}aS{Y79 zOvZIsXsWB7QXr(2iS{Zh6GdK`j1X5QioEi_{zPxhzn!H%4w>%&0000<MNUMnLSTYP CgEgxF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce4839e02fd3f17b5fd8e358ff204046c38d26f GIT binary patch literal 1344 zcmY+CSx{347==TqEn;1Yb)kzRwvO5s8xTS1=pdpEBQS_s6{;)(R?#BJSj4Jq3RJBX zQDkYPh!_@AR0IrxkdTEC5=cT4vWF~}EH}AX?oB|$Ort*a;rwUL%=w=FQ<a$T<6{5M z{81>>;#h1<lGj7u%Fow(H%%9op-|{MiE#(_c;jQdE<1-e#<7zI!9lWxOtDPx9D+$F za|9Y;+1PBmM2g7e2w&iwoP>oUczW7R8US1I0KR>uy>o^_wbJQO_e)bxulW@b<ZvB4 zo@1B>(HS=8h)pa;>PUr2w*vp69j|&N3$LV{>k!lrt7&peF2@=_WK3t6FL1zCrK1;c zH7nuAD!5GzQ;lwx*-Zivior!Ux<t@i6v-ISq51BG4od>61lETNxJ+QH5ZZ2v>;w(c zr$;)~&Sx6uh{@f|NG-y(<=?}pne`Kl{^u_ZM7rq_Go5lf9JaG;VDH?l&W*_Qz^qE` z(rDcPFl)8GZeeAZfrp4=T%kmSLZ?ImE0ivyaqclYvz3#LAOEF|e_A$BCFnXQ9V7Dv z_73408`uMxdz=u{jY#L*+Na`NlkRVmw$Z4rw*oI<I~TTdU}((ckeqDT`iPf(toCb@ zT??6djMEJURo#rD7SwjRVJU3mIH578m5tcNm+*=8qsIyfJBhqUufSr+@WP;cFeAGU zOx1wur*5ajX&H5xSqLO*8Y-zE#x-)&i@KtYKUhz+mi9wsb~6oB6U@p^NJpMUrV*>q zZCA}es>*=`951s&nb&8&N(4(twsIRVWR$lXrFet*iAB}#cBo*>Bn%3iW`PS*7^Q7$ z_8+Q|3MKs-z-xxVNk~tFw8K^n)nS-0h+9>R>&oGB1*KF!-sCj%Aq~|!O|hzn95ds< zWQ&4YCLb!14P4c6a1JBSs-{>}Ll!034sgw~K0UWdJBBk&^&l3R0~ojKxv*KPW#gp8 z%b<J^8ZM=HN9j|LlyCqQ1x#go!@_geqvySjeW$&woSohR5F4}WAeMO|ZS{hWZ^o@H zjt<~cX=Bt;2A4)*(K*93HuL+nBQc3L{_3j4ufE$?-cl2G_hx4!iJHcXCZ>+~h4>dY zSFdYJuBo}Vk>A|xk3MZ$+vF3p@YH_cBwxfkBosto!jdAwL$+=?ya7+A@<*k6g(9w! zvR@G^meB8Yt<;>!+s)T3aowoc;8%FDtaxd7@E|tX<MBnKJ@e?Y(o*z}vfa_c)PZNG zs-i>z%K`%f)vG>Tv0{ZT@XO_&ueyC`AKI845G$^ZA*NQ}>28@ViTY+6jXxB0|Ihe+ zAGQbA9hF3-<mczxr>ZM7wVqPyI&zbynjb2^vgu!ZXGXE!his~s5{t;!8Lhxdd2+H$ z`a^M1P2{d350QAO=#A%f!-lxV@)Wji(}5@Phm(@(Lzd&2xj)T=+t1GfFXQUTsNU3- z3CFt&S^TUm*_%@dF`1P<NcVl;vpy!2^m&H9U6|t$5mLzMU;Ubr=F|HHSR3Eadqx5D zUS@KS_2<1=;NKL~a}pYy|H!jsP2}&ojk|&;3b$YI&{zkqJQ;7?@f+?)@T$!?Vu1u2 z6*|R)<?x~pmIY>P?D=^xPs_+6o5h4r&fZYnYKX{H+WIe;MNe~RudnS)#<~{;28H`~ zp;7y0eV6*_*%98?uP@khq#!fBAS?1jewNozp_mX%a7bt{Cgfl!CNgYGWLVg@n5~f* t%(lAqYyJnE&CNWOeepej+5QfA+m6J9zXwKZ4|RG0RP3IF7(#Sf>3<opDS-e0 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested.png b/web/pgadmin/misc/static/explain/img/ex_nested.png new file mode 100644 index 0000000000000000000000000000000000000000..15c47316d5d4163d97b95cda99b2e3a2049341c5 GIT binary patch literal 1108 zcmV-a1grarP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002N z!qAqP(SL){b9d2ZYtf>m<h8fzyT0th#P7ht?ZCnA!NTss!|uez@5RRN#>el+$nVI> z@W{&W%FFS~%<;_4^3Bfj&d%}9&+^dF^3v1u)YS9U)%4fb^{cMtuCeH+s^-7I?YX<_ zv9sxtmEUxE)|i{&!NTpPsL;d2(7e9v+1d5IzwF1wx2vUWos>nDi!Y6V8N<SK)!C8X z=A7p9r{wXW<M5#4@SfuCp5pDD;q08@?3>`~o8Rb}-shO$=$_f!mC@3Tzr1kL*o)26 zebU;8+TxSc+KR}^cFoU%&Cc<&uw0mqEU~Ov&d-F$$aBxniISDkwXlcC#=6<xjNRgy z+TW7e-jUhekLvTc$jR@iqGZ|JkFBog*xQf2zwOuBjJLS!xVh`s*o@`wtmEsW*yMoL z*Nf}&z3K0|)z^yM=aJRciPhDL-sP6m)QFdjE7;qU%*}nTs8!L=iO9rx!oF?G$b{0> zhS%DTytZrH;g{Fej@H)nL!K(600001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0t-n*K~zY`?bYj3+CUHha0E^Sm0C-!f`UTD2bF{cA89RMMd}k-_8X`@6D zMDcCwzpmmq!zFho^0nPBncU28_IB=WSEKnK57DI6=@B#ZI&Bj!nhh;RQ)^pWyU}cZ z)A6?RoyGFL>qB>s)oQibdVBlq-DU@7w9Wkk{RS54bh=CqZ4J>G20jkDS^IJi4ZF;` z8lrbO21iC&#g2{)nR@g!3&`nlGsS~(TRx#$;_)EO3xVtkGWPWA<#-<`!pC#oDzTG@ zm-7e4Cnl!^LHPV-`fD&4425UD%|;##g>e44==XU{gcqWVOA$^@mY1u)d>}fv62tcu zi?6P&^D2@+DDn7(31MX;iI<(+h;RM?6?qPr6k<u`VluY5#Uwyj-DZ&~GD!iwmYp3E zNvTN!?e11h8X!#~86`=e_H5Spl!p|M$tel4d9vA`ebie9IZ>Sj{rZg<Sws=27lu-c zC{alo_Vx${Bq~Y6em=jiHXz9~0tdl-K6I!$8ITL~EO2y0s0Io}dif9vlTN=_Vvz7L ziImF>GJZ_B{3m6ZPJE}8xcZ5m`Oke+!p|<Q#uX3w<m}?|il?`W$kJNndTTqC$=!&O zB+G?jsp7x9xaAm4DY72;gNf4L^Q&7%Q+ieFtE0i*;iR56euwqsx`u@l8x{?Wqy`3G z1LL)UA^xw%J#C$lG-cRqEC2uiC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$c zGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLe aHY+eSIxsNGmsP9)0000<MNUMnLSTY)!c1@g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c0763337617f9ffe8cf13ba0f47f4cbc228c5e GIT binary patch literal 1741 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e8a17d409343ea937e43ebb76e8ebce3cbee49 GIT binary patch literal 1679 zcmV;A25|X_P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700093P)t-s0002$ z>-np$=8KNpd41PrYtf>m<hQu$y}#_m#_z+#@5IIL$H?!<$?(d{@XO5c%+2!7&hpRD z^3l=q)6?_S*7VKI@x#RKtF7j*vgoL)=DE4*zQ66bx$D2c?1{PCHi*G+tJ9jp;KbbR zwYTcBwCR$T-*kA@b$Qm9o8iF0?YO$@#KrD!&F)RW>0!p}cFpXj-txER_NL$Tu;TT) z=JnF<_`1C7tgh$6#O>_u`M<#JK)mS^tKuxP<Vd{ciPP?%-Smjn@Rix|quuhv>Gr_E z?!CY5b9mKtde+Ix@Y&h**4Fgb*Y&BOdclu2o|AU6wdkn3<nQj^z`B8`pHQ2SHI0E8 z^zq5??6>9S_}}36;^X(`=J@XJ`oh9?)!UTb=bh&Crswpj)Yy>1!FB8ApWWW|)z$Oa z+4SAs_UY;Q)7gv8)qvC7hU4;`;_#Zx(|Xa?iNU~h&Cc=8&+*mTk<Hb7)Y^@-uw0{@ zKg!X0)76cosO04HoYBpr<>Je;uUp^il;Z25=JcbPk1g@=<KO9(;OUv$y@|-HgVNLS z<@2KC@u1)6nBM1@<np22<(BL8x838F@a(p{wRqd%liupom%DYk(WC3-p6cYC@9DI{ z!|tuG>BYtG+TW6au0nIAH<`S6@9Vbj>b39av-9o7yuR$&-H@lxXLhSQxVh}u+>fx` zbW)8O?&h-X<+1GIukh!=*V>J;;C6bkLFU<&<<^tr(~#=is^sgb<LRi^*o=(8QsmW< z<I<1f&W!2Ur{U?K)!uy6+<M;RoYvQh>)x#5(2e2Ei{Q$M=hmg^@4C|3c;@M~)zyjb z<G$w9r0m|h*x!oR+=$fFiPY1F=Fy_%(4pkcpX=GS*xQZM(uUl=fZM!&+Pi(@%bwZY zlbDSxmyIjb)Qj4?e%iWy$HsK9saCJ2RmH+^(9MX=%ZJ0jZpp@epqD$y#d^WLYs<)l z>e#luw`{_{ZP3qu&(3_myJ*M5c)Yf2*42*6#(>q;^w`+-+<e(}00001bW%=J06^y0 zW&i*H32;bRa{vGUNB{r;NB~C3Yd!z~0>(*1K~zY`V_+Bsj7-cdtSEqmnTZj<4mNfU zPA+av9$r3v0YM>Q5m7O53A}ok*d(PSrIEGp$jHh`Fu@hbD}aEa5(p@RMVM8jRMpgx z-KC+arLDsZ*P@`Sr*B}WU}S7!YNiAhVKKK*v$R6C*UD1UT95^y#m3go-a*09$=Ssf zqJ`DX-NOpityZ31-mG|RVRd(BWk3V0KE4PsKYtJi2n2y3s1_NpbZ|&$Sa^77NHDq< z|A@%Q$O!+a=$P2JKx8e!A@K=`Ny#axAU&vBBGb~+BK^}dGPAN#w1mXx<mTlU6c!bS z5Y|#s3X%>jE3c@msw}Fm2_>kdmX);@NQEcYRn|AuH#Rkg6Z8udgtz3kwlTD|ws)Xw z=>&&Z7dXVaQMB~*hJ&cSe&TJJ0MXJvF`Q_>OqvANGI26iEmM%R)Uxt=f%Hrb51$Is zGI<(Y%k&vDp;~6mo`cX*%Q|=7y!l{zAnu#C0Ip@m!bOY0ep#|~*>Z$mSVdOMn`bQw zcSiVvm2fRH7p+>o7&F9xK3Sv9ie$^mwFti~UcGKT(3a&JHg4LCC5^%SvUUr?mepIg z0d4W$xP8aYU6^TXYWVIwAU)w*_9FbUZyVSzoAw_#cnCww)bPVcjvfQ*3Ez7hBg9Ue zJazgEhL-TN6OW!-a6X(N{P+coc)57!%%#g1egXRA%2kkW!Y^DSoW`KuhlDOe__ga8 zwp_k(^VV%FAr`*!4p__GyBJz--n;+cA(mVj{%G%GVB&vr_bG;!ThE?9$EGE$=EX~3 z7JK#jO&GeChtIKV34QzS{i_eJK7RU)k&(YVeE9GS7Qcji{rK(m_a8rh{SF~E#DYV< zetz@x&)?seg%U1X@DzPm{DP%`{fA!*wqpF>e|%c7Ru(cyl?A3>2v$j$Ax5y`!vthh zuVhr>BNzYx`KOJp(wB}a0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3d zIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(Rg ZD=;-WFfhuORjdF2002ovPDHLkV1g+E(G&mx literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_recursive_union.png b/web/pgadmin/misc/static/explain/img/ex_recursive_union.png new file mode 100644 index 0000000000000000000000000000000000000000..66952ea454e3703dcb08251bd2273193aacaeb28 GIT binary patch literal 1224 zcmV;(1ULJMP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005?P)t-s0001q zx!X2~!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_`zG-s;qsyLGzJqh@Q-%+2w=zwN)l?ZU(F)710W+4RoO^3l=q z)YSCg;P-*9LUN@xnY?(sz3iu{=c=sduCM9E#_!9_@xH(9!ou#w#_-nG^mC;*r_X10 zsycS7JFwk!QjHmRt30ycc6zZujKETQu|cJ%<dC*(*yYQi#9oB3MRKDxqQ_vQ%44U^ zW`?#&cB(tB+HrWUKD6U`wV8gwk2a0LQ}pr4@a(tn?6&Xfw)5}D^6bU!<+1JKu<YWm z@aVy|=X~nqo$BM9>EWC2=(Fb9mF3ry<kgbv-mJOnfA8zI>f)T}-<j^_vh3rp<kXSl z(vRufs(PNOy6%GS>9pzKn&{q{=iHa<<FM@Dt>n{?<I#@d&yDHXsC=|Tyzqqc?Z)lo zvGC}^@8-bj+^Xr?sp;6K?cuzZ%w5~PiSg>g@8!Sl;=SnCr{~qB=G3I@-MZ}IuH@B` z;?R!h*QVdchTg@6-NJ+A(V^?#t>e*;;mwQZ)TG|TgxtV^<<6ku&Wz#Air~qK=F+3x z!Ghesf!n@+<jtP$<G$?Py6fAx<<Fqx&Y$Ypwpcc+1poj50d!JMQvg8b*k%9#010qN zS#tmY07w7;07w8v$!k6U00Ih0L_t(Y$75g^1>^xnCJ=y<#A#t-W?^MxXX4=G;^tu@ zQVTC1zknc<kg$lT7_nMNw?!Q63n)p*ixQGjKvG&pR!&|)T2V<^MOB)R<&tXZ8bB?Y zTG~3g(t7#^hDOL*uzFF-*u+!=rxxs9)G#x*z@-Jd7o{w%tTk}?1-r1MjV;hGcG4gK zB^fj<EbJY?TCiG<EyOGw9i6~>aJZKN(>M(aXP_REv;f1z+0g=bbYa!PVBrGNg6c&y zE$GHsxMJD@@iq)#7-!*Tfnhl$q2L6P?j9KF2$E260x1tqFN|~qPAIs6hL^VmnqMFZ z1!u;P^700z3Ljq(fRfOJf-}iV`hlc<{R0Anf_+0m!@?tc(LxL(V^~CjT<see6&(}n z8yXj%km!r%atvE6lE7M$Q({uneADAIGPBUNWP^PHCBa&9z*=(i@(T)mi;7E1%h0u; zIvN;W<rQEpm1$Ll)xI^gb@dGhEf7DUI$Fb`yrL15lAFL`1tk&D3{C~8j<(1F>Hy^z z-{$b5#1`Myw)T!rge{O%fa+*?uJrBd&g`l4?d|KIFcHZw;8cL!(G0$mCYMfW^PM_v z!t@zPwt!Osc1JV#*3O(YyWMxr+<EgCAhbYI0d_|-_%5vPow~?(@sgzrmSKb#c1Po| z9FL>%0_={)uLY~4@dA8~9tHFV07F>Y9b_N@c>n+aC3HntbYx+4WjbSWWnpw>05UK! zFfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GK mIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTYtrHx7e literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_result.png b/web/pgadmin/misc/static/explain/img/ex_result.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd7b5904f9b304709ac6aab37e24dcc06d233c7 GIT binary patch literal 1320 zcmV+@1=sqCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002L z$<UU#(67SKeXh~4!_bAX(Osq0Zn@x(wb8-K&}gpOjmqed%IIXO*vQS$YP8;l)bMe> z<bu!aVX4@+#?YR;&}^sCf579B&FEmJ)}GYufxh8%tI?>y&|Rq4YRc_yz2s%c>~px_ zSfSIA(d>o8<yxZCm(uK6qSJ1{=25}wjkVEryyK13?q#joj?L+~#?YVI@LHwSTcFW` z#^!Uh-Idtykjm$8yW%;y=Uv3<cDmqo&Fy`{<dN0xWTeqv!RRu#=5@;IZp-X#u-cN- z?P09iK)mRBz~p+$>VwejipJ$*z2zga<UG3PRl(?g&g_)c?q;&xVZi4cujDnj=ViCx zTEpph#prd#=v=(zEVboDyXJq$=zz%RWX9`=(d|CD<!s68Q=QRq$?2xQ&}6XOaJJrj zx!-lf=SjZld&TESz2|<->y*ywR-w~O!0LI->S@2`Yq#KKzve-^=xegvb++DV$m?jj z<BZ7Wg3arCyWyqU@K3knEo+Lw00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0^dnQK~zY`?N#Yh+CUT!A%sLMsaGh-LM_OZl!8#apdwKLmBRyy7FwkURz=05 z^{DN?-f#qVLv*HJI{o0AVTQN6zxUqnUBR$t`S+s2aTTPh2@R$Ze@_Uhr6?^eX#=!w zkidu+dYpM2@p6b79vK~LYpmgw(Ik4&kDGzz5roD1dV(B&W5e4B`=q1wly#1~+^jML zcsL#Z*85J~R5W&<&+Tu6-BT{7A|X|P;{qx^*y6$v?}zk~X*x7LLn!g#XXoaFl0t_g zAIP46<ARx1fJ7H#9?<#k*9uEIb&ut;cg5uICm&DDQMi=5<os$BHaEGpPRal*X-K6r zalBmum3AqcgrAV>8=EE-ir5<7j^*+nDazi&@X2h!2ImzwkBpdc1Oj$;KNWK&&*v{K zHc_Fp2T>6_XL(<6MG=Sv0DC5#0-#mAvC+Nq*9v^kIK2l8vdFM%Et8knvxnJo1c6|c z&4c}KvKHW}Vy0H@L~i3sM*z8wP6~1|m|;789O!rkC-wRX3IT({=^1*&oHufd5<hTM z>Vx<$E{y1rNF{wq{1pVhD#p6C2Rn5oh%7L0oleB1N|4Fp`jMQ=#pw)z990@QuA5do z%zYPv$i2ZQ&zL%%$z6BtR(}-AOZ|1ZsiIV3#aX_aKKpI?Rtwj<S$$bw@^{6#TF;1K zr{3RVX9kpAD%Y_0MwLA*6vA-iVkfW3ieG7@w;>~pUC1Wk{1EpWn@(i<$E=y+6>NkK z&qpAySa4-uHvH^XzT03OH><a{o{ehAyMj8w$h-WttQ&NZpV96kV4My?L0ABbMGMDq z*$yScYY)=&)1fH`v<WoU-7VJ2U7}9J&`8I$z8yYm`gKnZK)LWFQpDw+wQo`T$%m=d zzQj%A4ia8s<V50kDpFI}g$%88-LN9{Um<<~F?K%Tp#n<Vv$^~qaIuPR*#L_H0A7VD z3nOkq=7|r|v-~&m2P92<JOAsn6#xJLC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@u zGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL< eG&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTXtOrt>n literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_scan.png b/web/pgadmin/misc/static/explain/img/ex_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..396dfb4feabdd85e081bf8336304129058633c5c GIT binary patch literal 1320 zcmY+CX;4!K6or#E43U(&OiX7G0Tmtd5DXYmgR&F@acWZxiv&wwL>3hgrBoq~lr@it zLJ^duAZWq5fw&ZkC=h`X77>I3W&snjFJvdI(x|^WbI&<*@7(X#z04qTpskIa4Gade zJw!T4v82aGA-}XZR*;$vgTXU`4u=peEwhE|na4_cJ>&OMPHdC^GN?%#(geLygmo&i zN3_g;wJ~hf>0VV*pQ>a+SI*I098_lwt84kXyOa8Y(V1&wnnwbI)t>@VyL>~#^s#Q` z-ez%7n>4gTN@YnI!|M1RSrS`*eOyDod9RKoioG$+D)iJTAoVnDW}2o~Kn4Y*nFci? z(4d5jN=PdLbt2HDg!CeCRtX6-W+}%-_OSp37f^A587`pV0tPWSt}w|tfRYQSEfXG~ z<pD-9I3_n5EVvjnE1@|h#C^#el^bWp;E2qi;{kdeVBi5}F*q#M8+pK-7&KX20?sR; z1r;<X(GQCC^Ad1T#TXFlOnku12j=+L1qs+M(#`ULMG4q9t)1s%*%ntpODaaswDupN zW=R4rs~Ft^&Eh0>X%f3E0nHYQkNqG4U%j7Mp2U7oF*>GZTDYnYlh_prI4U=^O{(k1 z<RH8(z;Xk43WXdD^Oa1*TAEd7Nz|V$N&2LK-gs{q?2D;G2mL}wJ?au}Fvk}SCEl-Z zn!Q~=7IE=$y}e(yGh*kDXdI~~U{jVK(F*Yxuqnx~>1&_l=Y&sWTE`Nqyi*-+eA9Md zK3zI6YurED-VlgxD2VgQq4T)o<{Uc52dBM4_ns4qT@<Dvt#*S#&6df$?z_JA^7Nd& zsc>|3T=BIfA3pq|mf@Ygu#{_8Ub(bzb>X|nwg*!@UBbMkgoVpZr*Tf=$$yMQS7cHv zJl|yI9uG%_?<;ufhl(nz-b3s9yRngm7!eBB**@c+iOV>**WUgtxir4qH!Q58sBY^X z+t^lqCrqiOuN6j!FCm^Z-Pw}A4cEdyv#acY!)jFJxKh;d#_(duq1<!#u|_inUhRb7 zZuWs4?RmPM3Lb48C_72VNCv(-0Y~+p3u~M&y#z-hvq<OPO#~HPL|HeT-JBnDa|-Q? z%<Wv4nUHu7scz!F?nr$`t8(+1oBKW|Pe5|!z>mbS2==EN8$unCzu)=|NpXJS+8k(y zsf-o0Hs=vz(jedS7h1^)Nk6Egj#I}j#|fGRi^DszZaa6=0t<S~OgC$5;PxXZf91sE zOWU(6NzTED<doV?9Qs3{X(;P@)9MkAuHxQkhHpV(D8foPn!Wy&AP<pDsLJyP%3oh& z_cAYs?`!v|IYy!w<2r@-;@--2?03|0W>xir$OP}|H5oNdm)-MvQ!!rm(9c)!#r=_M zBHea|)}|e>!%!27`lYDuS>)H4O$vGq?bkY|V%O_yDBIEKFR-P%ozXV=^u|^833oyO zaZUL45Q3B6k&=}B<!$*W;*kcVXyLiC3y+ARgakaz>j~!U7+UU*(%Cey-DHB+7FHqH zPj|}S-*ndrRToh|R<X8I9r-f-LcEN{x??i2OZ4-b(JqNaSpSxvc22t`6N*Rz>U)~O z3XiIz)B{0V)^^ow^e^-{bxVdh`d7qN(nH;q3&j)u%b;lk?cGMHsP*lX<>$Ai5W`cV zkEg^CP9(=z0_K5p$GN(DxZ>PHJa7d3E&?9!g4<2N;r5nqb@(5Um=t{~HtjQj+xH3h axJ|%$eg^tVLmyfI*dZeMV8gextp5Q0yRj$$ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_seek.png b/web/pgadmin/misc/static/explain/img/ex_seek.png new file mode 100644 index 0000000000000000000000000000000000000000..130fbd8f53ff5c2c757c8173eb62a1b604555f34 GIT binary patch literal 1326 zcmV+}1=0G6P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=yH~!hN)yyjTym@HuUhw@a(tm>$dan$M5O1^6ka$=CkqY#O&j+ zp~PP6<(}%}obT$j>EN30=(FhFndjV>?d7rN*p%$xt?c5j<kgbw;jZi7t?lNr@aV$t z=D^3Qb@1lE>fEaD<G$n4kK)jc>Dj2{(~#oMjN#0S=-8+2;k;g#B*DnK#F|j0%w%+@ zIG(kKuGw+%>WA&)VD95x^XP-`;92wMfbif}@ZVJQ=6#RAQ?cH30002z+A8STDCyWG z>eeFb)Es@XL#xzmv*LH^)gSEB81mgwaGgbAl`r+=dg#}t=hUR^+_~n_qTtDi-^YgD z#D(V5q}{`W+`xk0$cWs(faK1gsoHLy(PX^vg!0`^^V>}K<977gNQ<j%pw(yY&=l^^ z5bw?o^V&-A%?rQBx1!f+zBxuV00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0_90WK~zY`?b6v(+E5e+U>k6&Tea1i1BihN$R<*($RcX1MKFRGK$JxVf+$KW zhy}F%>%F-wiB95-Go4N!ybt#&-#z)Ab9#DS&%Zx!2<}MUVuX;%<?>#luYX`*kQjU` zlMN9=eZ#{e#K`E_*gHa$$j8UW<wXC)#Ke2z!{p?ojOaytm>8X!l8q66sme$E&ysih zt7&qYC!kO&l?v`wDPTseR?osLMNt~iXti1mw7()hkpiNeo10UDQm51DL2WP?=7BPr zOlHtpEEel?M1_c&BSs1+lgXro1&hV@3{im|lX;^N5wpo;(ZZt5X0wYEg;J%O;ZuCZ zDHa^yu-ffQqT~y3NAec0qSvcYm3fLnRm^78CC#GM>VRdZ)43x4V<?4zPhsh%aJt-X zk2q25T8%Zf8@mWro6YM4r`x?MMbIodjcv`s?sd5kS@roO$Sh8w!6_Vq6e}Lj+B#1* zzIONK8}5wc-65M>-;p8xoPq5?Ah6xNgTWoxp=o*tc0-}?Ubo6-WNU*YN&h}F5MZKA z00PlyGyuU^EFJ{<;NXCUP$H2C^W-qHdF1!+CzB*1Q6`E>EC|7PJWeB$N`)YtNT)MA zA&*Z`6(sm7u~>_s_vus$y&p~s$r0`tnG|LTK25Qg$z)ESkQa5#FPw|RYPB!JQhOF_ z*>zaY<#Kt*vn-njQ6gLqkFQY3Lhh_sJO}ooRAReiUr6j;FJ6yTv>w?);W7ugV)23n zwp6+*OAwdK?L_bUd~1-sJUh$5dGP|1D*;IgiByVwxm@mMIr;J89XtMch<EH7&xM=C zF6@TGtyxq~;j~(<-oQ<*R=ep`xsCif<aX?uGe9#bCe)sFre3dCpxS6Q@1S;ne_!j6 z-?x#6<TXBM$LJK(U5`q=-l)P|v)QaYCdl9&YgGv`2__7gbiIy9qk#$c@nh0%Tq{c_ zMWvPEu9M<XmiBo`$6n9>cm4nf0rwvzb1L2d001R)MObuXVRU6WV{&C-bY%cCFflMK zF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGP kFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f_kQ{fB*mh literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_setop.png b/web/pgadmin/misc/static/explain/img/ex_setop.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a9b1983b5b47c96ae910e73ab4260ae9c28b73 GIT binary patch literal 1143 zcmV--1c>{IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002E zxzL`V(1?rCc6!ljZ_&-ct;w>B#-wM%nNGrzJd>5te}mbYo#C;w>b<`0$jI=)!tS)S z>Yk$FfrZ(}s&>qySJ}LM<k6by-Kg#6v*XQ`qNLELspq@A?YOz?x47%Bu<78)j_l>D z>*J&8;hW6M%aoVjwzuoBvgxw3>bkq^zQOKonbT;Cw%F6E=-!y;+?VRzrRLP5*SC1B zujqQE*JQ2NWs|?=+Lq|snys$rs;uaQsoGkq)?dWwX2$7un78KHmFC!#<=2zt){@q> zb)U22NtVh}z2-Hy=1RThb;#&boz14Or{vX=<kXSo)|jNH<fy9WTeRLOv*bFs<#o5* zUyi-x(~#rRkKMwEAh6_t&FbUOj<dAt7_H;t&Wz#Ai>j^WVVTb!u;hfp;!=vh;meBO z#*ekO>Wt0lK!(EL%8BLApgM`e53A#l)9m2Mh~LPG-^YjE#f9R_n%=~P-olRE!h_qr zgxtV_;K!5Guy4}DpWelaCqTqQ00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0xn5JK~zY`?bK^i+CUTrVD7hwTp9u~3K&4efQ155Dpjm4f~c)k&`L{%-n1>) z8Vm%m{&hD%k|mfKr!(y*&NpUw=DfQ(dlZUEP3k|EQl-{twHmcbIry#98;mBC(V*AK z0c6TNZLwNy_D3iJkj{ZQUHHrlPB<~gy=WGlv$#E8ug7AuTIbPOJx2O`et#ek@cVEQ z(~p4#WO2zm9bC3Ac_=qPq43IMANT)2Boc{6p2Xsg1qngSR4_5mlTc_inS9EFXf&02 zhC3aSREyMFdQBwH*EcfBO%4E&da?EL)fS!|$)-f@i8MsEbNQXZ?%w{O1t(s=IdEa{ z9UyO)4`C8M+9{SY$0rd1ygNNTC_~YdQ=T+TwsVE|#Zvym-aY_BQK?j7P#cx`;~Y#@ z*NbPxQepRaGbMm(wdRV8r%``OjF8VqUpSKa`fZqr1GRJF!XOaM_w)$K<<I)$$4{|E z?Yv%V7zLtrAHsyXEd1ig#_vn9Mg5AVV<tJ`7D*pe`=HruLPQdb$`$xve5NY^u4%^j zfaCL-0Jv_EZNmdDS!~f_Sppgv`A=CNwrBy-V&I993`~e0m^z<{1x0q?S(Y2i<{%R% zy5-);Sjr4PEwt!%S>{IaFeOjS2A<dne{2A{WhN_mVq*{45?=X3(8Ek!_M&$)_K+p( zBEhYTPJ<wC!A;%vn9e=xqQ8_-b8vJi#oJ7y!L+k7OG)t;t8Y@1`X_Y<dEniZp!V7a z0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFU zC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ov JPDHLkV1j^qN`L?W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_sort.png b/web/pgadmin/misc/static/explain/img/ex_sort.png new file mode 100644 index 0000000000000000000000000000000000000000..1d46fd34beee098f997529bf0b7714c52232a2df GIT binary patch literal 1157 zcmY+Ce>l?#9LKkGD0JGb!<|bOQ+Me`PIBs@X131ubm*x$mvXaab;*yACb5J^<yUCU z=?G6fnfz!u<i}*hkYy7xW3|nXjiOR_@wspHSATpy@8|t_KCjR7c|Ol4eIL!oZ1p#* zQ7Dudg-rBA)cHdg8z6b}L>w1|LZ92`8{m!DQ{|nmX`=An**#5DzO7UKZPUMtXP6Il z5fWW|pN=clXUJv+$_1mFs&#^Aj(62w4Qg7mCQzhhh$nO8bCLPQz+!<`3u9yCLG%bb z?15U4$&kq)mBQ#~6BITAuO9LqLIsSB)IkpP_6i{rRI10&2s?LDwdh7Z8fJ@NCJm;! zFd4t3ITfD?Q+k-tfKm+#6{x2Ho*jVkUqDF&&9OlR$ex0982Sc5B7<QifWi&bjP3!r zaEsx0$?8cB`nK#iITTstVily{c^X+e5er>i<q%g4k%ho6fRJ1W5&*YE99$-0RE<W} zX*u<}b08K&QxnwJgHU)0{BOZo5Q%sYYAS}-7f?P0MUzmdg?qD*qJqS6;3y$x4DvM) zseqCx$W=qd3>dXTM?bXpLR$}rBv8e3)XBr99y8x4qpF)h&;TP34lIsGOB-m{TFz%8 zmqJJT(fm=Knjt1)R-Gi%qYx#33{uyzT`1HF4+_yMfZVAcm^py)vTU8m)18%`sKnhj z*<uksYUi1eVOfJKPs>_|AHuUzvW>}&>XtFnD#12=5jSD-l}O2Xy6AEAsv_w~<-a~= zR<a9*e9KC+;FgGmLH*CMbBgT*1FGqRFG(blkIk<5_s=(bzrrV0ONLT{JvvNXj&wR) z>7XZDI#BoKl9GL|_MWroq;CqTDQRU3U&c7L*{b^OT#I7a=4*Z|__`WB7ft(h<#lmL zwVU<juuHW=)EJqm7n3feC-+#%HCxw=uD|m{yYOyl`E(|KL();vVdHgcQY}`jeA$Kz zd^GU|aTDfZM~Hc9Sy{U?g_H0ClY?C)4vFx^B<8H|$3?8%P+fzuPdEAthoRteGj^qv zp2y-%Cb5#6EEi(d{<;x1@Ul9Xj(^`H-CwfeY>d+eFuzNvy3((g8#?Rm4)+uXRZ{0S zek&Lj2&|vqTX>h8z4p+Yu5=*Wb*%X-%fX;6ZCeB97F{VJdvHeYIL!geO(qzY#fd~4 zgP|L%u1gYzNTmVY-#^*ix*}V#)w7h0IfJh~v<cg-uAtgBZSQdJ-+WSx^D$TOOB4TV z&ougHZ<*gtEH4SK60NlsIlMIuW@DxNaj!)u>tp7<>2HN#d3gq@q^0Jug@L!_)33u3 zSD40j=<&?;yenlDmRu9KMFjKSyr<uxY0vOCm{D>(4e9y6VRvwCmgKfwx9qwK@bjUR zis9q0OCHVF-XIovFSc|R*2(*Lx0j!tMXN^#U$e&f2a$)ekM=$o%{USr>i$P$C?Y6l zf)l~f$=Q+M6yQv7ciHCd;_?IGCwBtDjc339GvLo~Mi}$-CxEcyBk-Zyo#6Tj=q}h_ PfdD9qH;q`i`*8CAb@5|F literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_subplan.png b/web/pgadmin/misc/static/explain/img/ex_subplan.png new file mode 100644 index 0000000000000000000000000000000000000000..e13d7794e91fc0842702b0b34c1a9b61607dcf92 GIT binary patch literal 1283 zcmV+e1^oJnP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002O z!_bzQ(SL){ba>NdYtf>m<hHo#y}#_l#qYwz?#9UP$jI=?%J9p~@y*Wi&(QMG(el&N z^Viq)tgh&<vFNF*=D4}*zQ66j!R@lN>5`V;n496cyz8c@(AnDc$Hlj+rEHy)MVE~( zje!}GmC?n;b=BCB+u@bv?y2JJpyBGA(b0>*y>Y_8Zq(O`&Cz|**oW5HjmgV)&CP_q zyl}CsSnBe)wXlcC#=6+uj;W$#*yDlM;eY7uxXQ|X(bI*zwrqx}WKxY8b*9HQh{34O zXl={vL%r!uzvx%P>V?$sl-Tfk&g_TN?ycYR5Ub*n)$gj(YI2sLtk-VAk2du2$?)v9 z@9DJj?Z)lovFzcl@ae+p;+*H(mgLov>)x!v$huvZB(B<V=--*+(T?ies-Crnc&$CS z>3-?jshY`Moz7yq?t<^;!0Fhh?&7_NyG?JLL&vIhi>qwE$G7O#rsmV5>)g5C#f9C% zgW=4J+`xh5&Y;`Af8@=c4PV1400001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0=h{=K~zY`&6Md=+CUh_IT8h`QXz`eqXw2kLy;n)g4XJmdbG8avTB3Kp(v<$ z)p}e1_3p-?5Zu7nnNFV%o0)f?-@M1}Mx*)X((3dKs}!TxX;p}pR)f)GG8$jBwRd!w z%`ZDUEmpIMqcggeuI?_I0%_~9**P5z(YJQL>Qz?8^x17DJq=;{x!wU~4cdV|%WIZ~ zu$^Xx5QDtK35c8yeo&)jELJMwVp*3&xINyX;bB4W`rcrMwbBt;yniI{)+-1?FfbY# z<5dwki^CHb36sj4;gCDzP(xg7TRUOE_;`3?5(g$H!Vxb}L0qhf<BXVz0ua3qO*$hH zHH5VoIL=<X3)B(ZiOt5=WWh)fsJ71<dhlKp3=LHn5NrmCg5jxYL1vmmz_>6q?R^LC z+aGBz3y6${r7U>JZlAM>UNjEhXh=TF8Nd2bRuFzH;GTIO2?j%Mzk8N%fEdW$AV22w zL@?s<g=QOEOV-}=<mI>0-wW-D+06_Mp*`e&BlRIa<9G3lpVBjaeSfJrI7i?75F?V; zhba6A>5ka^!s61W*yk_H%U@$pB6W_~LOdQ{ip?)B&3~&x5><%OLCKO($?{#QQC=UB z<Ren&Kr5@OYb)r7D5loYlSrKdt)|oIH6(6iGFem^Z!W)?&s9dPbVz|M5s8^hVH*(_ zo>gwAm@Mw(G_XV%g#!oHwzf7zl+6?hyND182=m3g{rzGd!crMCwGM*d8pU;Vu)TYD zgz$MJ63OJ|-to!teyLO{m&;J$!1{@Z<P~R0Bq4++r@u~5@V88|)H+C(^;9Z*fR4`2 z&M%~1s%8btQZKa*97stu9$sEvoj**h=5i_>8k8**uFuf<<<-sY<GEC;&VjbCuSwwQ z=Jy>1Q997kA*u1=_V(_Af+!tz^Qco}$N!-}nbr1E9_U2o0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1oA>oooOA literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_tid_scan.png b/web/pgadmin/misc/static/explain/img/ex_tid_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6063a1af031c626802911fdca598983aff7d52 GIT binary patch literal 1074 zcmV-21kL-2P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002d z;PI2T-@Mf8{{H{L*6o?Q;ibal>hbyT^!nN5^vBrl+3WSI#^#K%-OAhV<Lvi^t=n~> z)~3be%jEIR<?+4P?Qx#e)#LN7$>)Ek+0f?l*6Q@d;qbxV@5$rvYnjrc!{ox+?t7-# zwb1FX%;=%P<Hg|a#oq4t`u(HD<awmm>Ezqh$F9h;kiMjKx|(3PkxRstJB*5mfq{XC zhlh@ij+T~|prD|vtgO7eyv@zc+}zyo@bKZ`;laPVtDlO=oI}p1PuR6w-oa?$%4zD; zYVFo~;L^J5>E!0-=GocV($dn%$jHFJz_hfqs;a7)nVF-bqn?|W>)wU&>3;X;Y4PG! z_2EYK-Z;soXy4!8*4Eb0(9p`t%EiUS?d|R1)xgxbiOHZ?)2mYZ=33Can9k15#>U3O z!^66|x{;BQ>gwv<&a=<QxxT)>xVX5tx3}Kg*UYkn%e$bxy}jh*<eZ$G=;-L1o13t( zu%DlwudlDArKN?1g_M+(;^{T(00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0qIFZK~zY`?UY$l+E5sVm1q!Z0s&d05EXH$OJzw&f>9JvV-~<xtzpr&mJ)3# zt^4}dJ;CwH5a3Q{crP>OnfJ;0@};Mzn|G656V%rsV(N#@1DyaC>j%>yg4)_VZtpi^ z4$R~na=AT7>*IZ1AL@sFZhUwc9|;5piB`Y>L|~&3j^krablejP42`#Fv4k9O$mI$; zF%N;*>=WT2Y&Irr9@rh6L@)yJTD0r+VpD$OYqp`G5qH=Twobo1f&7qh2|N*)`RMCt z5>^5=+dBb3rrVuclg!S|FML{Dj6`FxSe&F1G{YvB49;`QE2-7B^m-<<5!u}0xots| z<ZO=2OPoHy%R7<P^ye?Td;4GaGY3ktP$(AJk|>G{P073tp-|<+t)p+>BR|ra<Kx}6 zp9P^(`c;(}RaK?3e4@NYvh3lhmf7D8Y$NrD70Xgh{acr1xh^r;=Ey0}bN}Z4ADn5# z`7_Z35rLQn@fV!3T@cu3sYXRZOw?(q(U+=l1rYG!LIqTS4wb1%)v`)c*EjlN#riFI zORLpVMG%CdCdSn7?sHM{I%^=7WY6#Nxs&Jv80AAeN<QWi_cvX!_a&yZ5Yzei!HOA( z>8=<EC*^g;nl5r9OG%cY6BHS5^LNqB+sG4UmhG=%BJ%?P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$g8msoqyPW_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unique.png b/web/pgadmin/misc/static/explain/img/ex_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..cb70480be8a4f49369d9a974ce9461284d1a4654 GIT binary patch literal 1238 zcmV;{1S$K8P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002Z z#KgUKcgI3Ps~Q@~u&}o&Ddc5l(9X`ss&&DSHnvqK%tl7dN=mayB!;PEQjHmZrCYPX zru6a2@a(tm>b0~uF5<tRp~YT>vPSFWp6cS9>EWB(wt%)SEA8a5a-%iq-I&LARP5lb z-DPF(<-exPW%BF9vLz+pz?JIUs&=Y7>DZ_2+_~o1l-8qo)LdNR&yAk7hpyUjc&<L= z)RExHh~LMC=Fy_RTtmV?KjF-Z=+~yT<a*t~g5%7duOT6OvqIz1kK4U}xG^!fML3PY zQ|HvA<j$bIJ3G^6X1VKs(35S+RaLw1gT_uymdstaH8rt4A-G~H%wuG_M@zb8Ws;TA zW^2)iL34~eXwA;?y}#|h!R^Ar?#0IN$jR`_%<--<Hq^DqyuItEspqP!=dQ2mv9s#7 zx9hx}zpN}W)z$R0W_!S=%C9#);NbVg#O%qp*3r@OwTrE~yX?Nd?W<8{vvZEQtk|zV zN|H5LgGPX=ey69T;D1YtlFETR00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*y&TK~zY`&6N9F(oh)3hs+U!xs^aDm&vUZae{%Mz>t6d6NpNgVwgoYFIh(3 zy7;emwsT-WPoD8Z&*S?eXP>?A`{nFI5QC)~(-9-qn4TPw8K(^79c_;qX;>yRGhrkM zmgDZ;!yxpe#VVK0K;5Sag0tJFa13pkb~v0)7iDnswA^I|Fc`!t6CSVG?Df&|5A2Mc z!yy3hc-(%<1rabC4w>YwJny3XHeUcC4=@N!Y=Y67XxiA1bfc8ZIN0SO&+|UgKRXvh zUD&C47Dj2YfB}5L&;mV(@PZ&Ly2G|eBm_^E<{w2_CCX`sM~Fq1<B1`}C&Xea%&Iq; zOraAtn&uS5sSu)=8Af8U2<cyQC6^Jh6isJYB}$L*I2jkk+%OUd1{d?;LMoL)BePGk zEL;+-QB0IFnW0^bN?v7?8Vr}lB^C%K$n~|kVljbU#y!RTm7(NDzETiDp<uWw4oSsV zYGtpCl;9o9;t`QtCtYGLmn$hZIa_^(yU7b1^-3X8DwULAxGEqp-;0rcUaP<81*7Gw zBy{A<kv%cHxiuOAn5}W8+b#20LxQz!W_B9d5|f&{uUdPr_um+(w~{uGN$q#<KYaXj zKp75?ByAo;$g$acEF)SxhLA%)^%){~kHK9IDF4aP7lhzE1{2$1^xKlu=tsIy%GLP0 z%U9sB({2~!v2K*jZ{34|T{`aYNox=7f;@(n{C?Iu7(mXM)eH3mdJKaAk6o%=pvP`N zn!Bw|K76H)j6C-5UF2YX)XG2AV35adO6;r+Ja($S4C^s4@~?d5s&8bh#{hC(D_^Jx z-eXexH}KeH7t!J|X}^=NZ1#fD;;{zEtA5=J<`#PF|I{BM#JXLtE~^v(001R)MObuX zVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn= zI&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f(A@n A@Bjb+ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unknown.png b/web/pgadmin/misc/static/explain/img/ex_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d54f5c7b253978b96993ea260828a144395095 GIT binary patch literal 1088 zcmV-G1i$-<P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-s00025 z!qAqu(2ljybgR*YvC*c#(8$fuxW>>^ozY{g+H$$zaJ}Pq#prd!=Xk~Eea7c~!sL0n z;BT|sS)tRx%FtS*)o#A!TgB^2zUV@{=s>&YKf2~ayXQu|=uW=pS;FaL#_4Uz>V?ql zgTmx#uG*ix&}^sCZn)r0!09iw<{+@-AFtyivE(VU<S(@3G`8hBxaB~(<wd*ZOTFe$ zzUOPl=~<%FSE18r!{{2W;}xvqRlw(3!RL9*>ypmuTB6fvyyGgg<`JvnU&H8?(CcKb z+6}7WW5noy&+LiA<Yc7LR>0^9sp2xV<VL*aXU6Do$?BHZ?`E*vFt_Gl#_Mpx=3d3> zQNZYfzTthY(P6#i1*qX$pwV}|;(pHSdCBU($<S58=^e1-60GB4s@Sl@&}p>ZUZ&P@ z%j|o{>5S9ub++Dj%<5;W*ml6=ipuD1!|15M&|t;sdd}^2y5K>(=xE66YQW}z$LM~@ z=wip~XUObp%Itj4?KV3{{{R300d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U z00H_*L_t(Y$L-VoSJF@z2k>#Zm$&&66HySyHefJJgw$z(fRdI186mP%OejOc)GU0- z>Thp&cTUGnWA_LBjqi^;_jC5#=Xowg_45ER0W(yCfW=C5-iGWBdSGy9_=%GlaUqi- z7)9=}agTSxH_7@rUI+w3XtcKw!x1Su^>jKm6Hh#wotx+6KyX3qS=8e5Xfl=jOVUex zCY$SJ(DF(?f1kYIGpjlM+Q3>O|MFk*N?zYUx};D{l{E6&w>hhkH|4iEy=IG*tr8}& ziR$)Hxu#$u2i^f4va_4qyCc)=fD6L<KCfW%UbnKkRKg@awqsLAR5&PNlF7pVi-x=T zA@#A_G0)+r?gu!`8IsoWZc$>r-g5o!YDdRuOx8EdI)ya=f(84cqtfc00Its*zP`{t zvGm*-tI5)xw)yaY^JDU5HB1@DiXyUq6VF9xpNhu9hUnU)HhsCxm`TK0GodYv9AJ>K zpwO8V$2+zpw@(TFp)QUR#cP=s&KF1o75*B>n>;TB;RT6Mw;+beHz%@@2+C4n@q3xe zxX1(rB0fx-PLf_>Qk9e@SL44kfRHrYjx{x*Q0S;ZNGK6#A=nd5v?4T3cRC&Bgw()6 z&n4?oZ*z4HNy+sL?wE4ZCuHQu?RfR}=da`6SyFNV?OMnlOFxg0KS=w20#>Z+^Z)<= zC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!q zSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMn GLSTY1nJ@bQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_update.png b/web/pgadmin/misc/static/explain/img/ex_update.png new file mode 100644 index 0000000000000000000000000000000000000000..a45c53f83a0593704855bb8488871e8e8c9be701 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003#P)t-s00016 zTU$1W!3nA2a+aZzl9IuXHZry4b*9Hbyy(lKSW3X@*Qid%s&!q&>iw+&W5()h$LMIt z>~72Kb<OPByMEiff7`u@<Gpj-zJT1nfd9QPd(rRQ!GeU*?%l(Kgwyce#Dw0(h2F-7 zjMVPm$A{m@h>_Lq;K_;M%!-%U@#D*$;?9iY%%0@Up5oAr<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp{Fb>D#L7+PCQ5nd;rD?A*BN;F{~+tnA&o>));H-n#7It?J{P?cclX;jZoAyXxef z?BcKO;k@kQu<hls@8rJi=CbbQv+w1=@aDkp=(F$XweaY|@ae+v?6&di#PaRM^X<m- z@W|M;qjdlP00DGTPE!Ct=GbNc000SaNLh0L01FcU01FcV0GgZ_0007=Nkl<ZNXPAy z-B#LA5QQ<eL#ah;5tS;UMbwA_5<v)|fIxsm0YgCuG)2mv@BaclIp+XDLzfq>)m}Ik z`zl|u_nwKx@;3iqJ}~+$R5OHe*le~9W_M+Eb)VV);&7ZYr@MQ57tF=s@$q-Y6tOKY zFWZ<Eq^rzltJUgYHW0qY9ImfBj+s~b$~)|Np_(D^I2a5bC)(@vMljMeZ3shERr^4m z0k9j9!To)$N40l*d;0*Il+U+8O{EeF5Mun>Zl6PH7^x9N(m>1S^C~n`i3##!Jnm*; zhV*LqVXP05gphXrI;BEA5sz0XlFizcG0d`H|I-vdaf)Ui`bxFjrCB!Z-`K&F`2_lG zW8HeL^u3$4uQLXA^nuZXrj20OZmUD+*A=A;U0IeplNZl1u(P(dwqr=q)KgrQK@JCl z;>^E+p@=3)q}Ws)l=#)94014dCK_tO3=TIzaIq>bwt5*3%TPQ!V{>4cXY2w@vpi4H z5p%f~7?%#4`cmO#jZGLtp*Uy@&3d0|w^~NK=oCe<1FcLZ-GKRfgiQARl7;%8Pr;%T znUf=*08efhU<o1hL;@WKQ8^qA7C~fLHUsG+pZ6(3LA}y4RZ?t@Jvm83((Co|<_PjH z|Dvj=XrUD8WCI!k&sR*5kA}v!pSNfJ6<IEJ=yr%Ul7estl~^=#V{VN2CpSP8r8wXr z>T$a{bA%j*5fQuxo)|>jZr1{YRBA-{1CJ*HoZICJnIoNCF4LOJQi(<*B`9&BQ0dhg zYo(KD3q<dDK30Jnj^of*LV-ZR+!#3wqPz#EaOo)mPN(zS97+20!yp>N#m*4FIU=Af z#HdEyIudfZoB=prjNI`t<e#W9MZxd)7yi=N)=U1%xA~vu4`}JQAOw$Lx&QzG07*qo IM6N<$g4z^C1ONa4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_values_scan.png b/web/pgadmin/misc/static/explain/img/ex_values_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..15b5ab4079cb8e2c015b4f5f10a3dbf8aa6410d3 GIT binary patch literal 913 zcmV;C18)3@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-siMiW0 zh{12o?m@ljMZW2E&hL59?@+?(R>SIp)9{Ja@MXyCYRT+x%IuWb@tNB3d(Q2G(e0$& z@u=SNj@0gw*6*+3^985jNWbYDuH#$9>o~XNP`>9?z~@=P=Z4YkYscts$mx~W?|Po8 zrNQK8meIkFHu36*?c-qX<6!dYhx6)(@8e(Z<X`jahxF@*@Z?|d<X`pchw|iK_Unh? z@Av20E9lxQ=-Mjk+bZnaD(>4V@7pT#<zLt8_37Fw>)R^r+bZweD)8JY^yOdH>GbpD zU-ji*_v?rF>xbLDiPY)z_T^vG==1U1D)QVa^V}-;<zLa~^7Py)_~l>q+$#9yU-|2Y z`s|0!=JL+v^7-ap`|O6y<?;31D)-$g_}wY`=3mR?@%G&+`{rND<M8?2DahmS`Rs@M z?1snV@W$fr{N`W%?1shR@B7{<{N5@3=3n>SDf-<h{^no8;O_n2DgNw+z~An<+wA_{ zDgWkQ)amoS-tDc{=`>ap0ssI20d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_ z00FH@L_t(Y$L-b0a)Lk*24Ek?nFomRW_gGUK~X^z7hFIQqoPPyTuOQNU}g{;#Yj~u zhm?Jq%hywM|1~5M&-$-bf~P9QA@C)YD!#&4B$dhJ^6-HRlK><UDZb@$)Hi|e6h+aI z7lL#eAd=5jtC&#LT8)Xk5M;BM1g#-eV_6OzX@=ukmluLU0gw}e6wC6MaC~zhM3C?# zXpU=qVA33nA0Xiih4FYO5~N%P_eS3qM6pMZN(IEs1gO_R%)p!pq$!4J!B~W0dA{*T zU_hti6P|CPal)1$2<_;=bi0@Y8wgGI=I8hOm;|k%FdTl$=-8HJWkw8nG`bFqIFuv> z5m{ALg&>p3bzpku)=*JRlO)sW-M}cOX=((S&+i6irfAxdAd5xpz^qoW1LG6e7Dc)D zP+)8u6H)Rf`%_@fM3(#wc;Boj%jm#tw?0u-yn)kXbuBtDXA-pbh^`yxxHJr711}%G z-3~o|;r(g)dX0&(b{s2Az~Sh+#{;pMQ)_F3i9?ViuwB>2PwdUWSk8WbK|JGSEO{p| n8_Tjb@b)wQYk!?*{c(K(wSJimSdJ6(00000NkvXXu0mjfih%ky literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..1f858be1cee3f5d8f2b67f55d730e6d3f43e9b42 GIT binary patch literal 2021 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..b51e0b3f4c61ba166b69bd7f32cb23dc8428429e GIT binary patch literal 1965 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exclude.png b/web/pgadmin/misc/static/explain/img/exclude.png new file mode 100644 index 0000000000000000000000000000000000000000..bd62eef6410d9315857d2e6d246770e8b65b8f47 GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47y|-)LR^8|wi}<ymTvVw_QrY1 zLC3?d^*UDhFWLA1|9`)wM`KREbvXQ5A-=(6%9fR9ZhU_6^4^pwS28lLWMw^=HS5>= z_isLZP1<@%wQ`Qjk=K%*nNgG09JqAnY+~Zm($d$dsZT2^E~KQ~e)?Lsd6{J1L`ko# z8QYH^XzhAZSorVPuP+-md|tBT-`~HFYif>6nkJPuNuqp?YIOD56Ib^8`rV6+d^K<0 zzkmPUtXQ!pGFqZ!hGg3swe*g4XK!wIaz5qe_HfFSrwbQu^AC`0S|K@Qk7Uk-*~hPM zEhsq<82I=1?;BI6UhV1m_vg>S@bIm*jgk|0NG?2Of9R!T^@7Cpr%znEwc5~Vm%sly zUEQ5NKC5l*c3rqFx8Q{2nrn7@9?A4<w%>5&&c`3`Z{FOOoV;9Hdxfs<!JM4Ox9?6m zenWfBW$A4XY?hzYUUH^<`Bv54PXhWDq@H_cwegx-ao6F7A05CjWh@Eu3ubV5b|VeM zN%D4g;b^-zwF=1LEbxdd2GSm2>~=ES4#-&V>Eak7aXC5R07H*Y2Gbdx45l?XZ+LiQ zWMmY~)Ws(}c=qt=V{riyAu&Nw;pq&V9$ucOPn<e=Qd>hyv$&ZhB;@K9Q<JS*N=v?e zImpD;=5|bN*|M}_&%~xBFluK@M_UI6S4XqEt8Zx7+`W4C?)K%=xA(7?_c&m$V4z{4 zVq&6Wqh!RTA|NX)Ek1w3j45*_&6>t1bmBw`i*--4qPDWM%7n?><t2V{=CjN{U1V)w zV3-jtUHUai{xs0(swJ)wB`Jv|saDBFsX&Us$iUE0*8qr2Lkumf3@ojTjkFEStPBi} hcbK)IXvob^$xN%ntzp~MJ}aOG22WQ%mvv4FO#q89Jv#sZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension-sm.png b/web/pgadmin/misc/static/explain/img/extension-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..432d2f44231c1f88e787091060efc5125d80ef64 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E0BJDv+cp5$Qv6qzrVk7 zW3&9@vzBik`G5Ho|K-)uTicc2-1GkNGyU0x%oo?3fBedPak1gnHlr`^;(z|izO~Kb z%lm|1zjI$+bN~H2|Mm{mcMpR9{3*J*S>f3^`;Si}e|^pQ`={jETDdE$#Qyy)dv><$ z|KAGswyocQwlbCk`2{mLJiCzw<Zu>vL>2>S4={E+nQaGT<aoL`hDcoQ?f2wsP!M2o z7l{eDQ+~(c|9@BE84^1Kx361bY|Bu`qQb-J62DBxZ_<p5BE`pwna}6wxpa1%>e!Vz zahdU=*X&ESFOpJE*&;e)`qd3*DpaT5u9JDLS%3P((k)@<ZbaLzV+h!Of4=?`KK92q z=3fE@l4^--L`h0wNvc(HQ7VvPFfuSS&^0vDH82b@GO#i+wlXo*HZZj^FqrpFZxxD$ o-29Zxv`UBu152<5plTB<12c$*Q`1A&05vdpy85}Sb4q9e01}k2!2kdN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension.png b/web/pgadmin/misc/static/explain/img/extension.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732 GIT binary patch literal 996 zcmV<A0~`E_P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%`cO<%MQ2zLf_6I6&9|zdd99>-@a*2m!Junh7N)|bRf|-bx|zVboSKha_w(lG z;mc-L4XVVcQjb)R!IoN>UTm6cdTlP+)48aeY_F(+!qvh)fIq$I$ak@QM1Demb2p-y zZNIpg%*U?Z+|0eUmR?Q)@#@yLtA3u9XFhv8mdv0tb~C!Ok)4xckc3Wsa4?*aUD?pH z@afX-<;s|gP-<HecxWLITMn+{ye)Dq{QLL&`11Mo?Dg>A^X%E{;lk+My5`xk<JGC) z(V?J^Pa0qr9%URUZYXJ}aH`|EXsd7=V;MkvKHbcisFznYY9*e@qsi^kq0p+c;k~!# z!?5MPqv5li->#6?p?1NAale3n)0NuDkgb|nMQ$vEwur;)&X(P%klLe(*qwsbn0(Ze z&%lqBg+*3S1ZY?dnutTImr{GNfpyZ2etkM9XCNqTCtr9wihVOAV;iN_u6D(TK#xcf zTn`v!7(bOtw4`b=XCQ>Lht=`it<|(#mtSF?W<QQcm$;T>m1BZ;G0*SUx8%WGt7&4B zV3D+tb8RIwgF3Luu#bN^7G4v==*yVRp-_@kjmeoSdoaG!zSzWv!K`UHUKC!MVuZSj zaIAJVdpAyF9vxyClh&g+jY8GGe$u;klYuouT@*iVD?w)>Y;7EsekVC?DRR1gZ_tQZ zyKv99ZOyY~z@}84hBK{_JHn(!l6fLVbTnhFZfMSfV$6Lul0qhGC2*Z?NP<TvhBL~q zUB|0c#ivccpg)Ro98G#WT*`P>$a6}(W;2>aI;l}Wz+t|fIeljlScFSfreaXWZ%f2# zMZ#t~zg?k^OOAUphI1*4cr3V}Qns8&igY1@Y#D@Y7H?b$T8UCtsbn_2S%i2!rk!)h z!>EaMCcvamyR?(W!KK8$qF<3+9BCaAUJ)8<9X6LmEss1DV->ZTL3e2=8EP9)hfaum zLy>wXERsEdsDEo(3zmE$ex`jsyImG&7=LOOfol~TcO*%INEmJ%7i}B|YRn1%0004W zQchC<K<3zH00001VoOIv0Eh)0NB{r;32;bRa{vGf6951U69E94oEQKA00(qQO+^RW z0~-xG4!&HBF8}}lR!KxbR2b7^U?3j2xS;VvLXbtwTz~>0W=QhVA)yH_FkL{}1;huk zpaKCQKz@=7s`{i97i0@vl2TS8w1C7?R&G7y;)1Nm<<OZkC{A-h<6}A<CjbDaP8qDe SR_4e60000<MNUMnLSTaX-^L37 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extensions.png b/web/pgadmin/misc/static/explain/img/extensions.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5 GIT binary patch literal 1017 zcmV<V0|xwwP)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%_fSk!MS^xZ(#^N3p?R&Od+_Yu$ibj%T^6RorB#bmn!1_5x}2JiUH9|m=i$p{ zRt>7esZx(rkHMB&m|kp}YkF-i+S9qHoNTYCfx^|oK7c>H>Bx7neMEjjfO9vZnQgzg znaszo-`vc-ww7K_0rBeAwyS=gm1jPCJeJI$Gj=n&vyq*XV~~VSeQ+?GkzLu)v+(KC z?&Zpui%@D?5_o7K5L*te<Gd|$E&TiU`}p$t_U!fW;PdR+>*2!a-MZ%4vg6gM;L)L= zk53w479M3BDQ+lfsBo&|xoE3!8)F$jd_LXGn5dUmHEJcE$)m~b(xK3*v*EqB=fkk& zzN6u@o!_pI*P(X7g>k=tf76xP$dIj?SVe9ugSLpn>&}+lsF2#DiP)Wj)|h<Mlh449 zm4!uCPy}dL4Vs8UtCv!Hv4M5cjedPPC}$ujZ6{xNJBocXBx4(;)vk8Mhd_@=5nK-# zWf(t|O0=YEF=rrzvxn93+^yBLT$f*Ao@PIeN0+#kWR+urcQMcJ*SF-sT&rnflVFjw zkaKM%G=n;@$*_-qITl_M!syGG&7n||RE^1*D|;}$)4tfmhrz6AIbIZAnqq{yi*T%V zHhVWtV;&u18I#tdIE_NpzkbrYc9VfMLtPX<ZYx1&B5Z9Om3}8VZ7FiPes9o-TDx%1 zw{6X{Wx%FXorW{5k~_krMv{3VMsze|t!`+}gJR5mHj+XnY9(-;Zb*VhCx$c1uU*Hh zRmG=Gz@R^havV*1JY33nR>*Toyk;|+MLMZbK)_+XojHAH5m<yvR;FT5#&1i+YDL0k zJHK6_k4uhwGlp|1i+C)!pi;J+M~ZYIf@~RtZ5D4_30jF#R;gq*y;+2KJ*J&=$it|K zbtb^1PrI~}#=)h;zM@}|T^wm05?&D+Y8^J0MJ<m!6k`>&nL&4HC>d%SP=`*4d_$3X zCoGaZfT(|KS__tZB7UZQKD%8OXc&KL7J+LO8+Rm0f=C!{9T#mJ7UDFE00001bW%=J z06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru+XEXB z6Cp(Rbcp}}0B%V{K~xyiU68R2z#t3+nS(tt!3~hY^vGg42FL=`EENNm0{M!6-y1;) zQxFazvL_cK*b<_okFg0d8Hc#V=Eh`)h+yZmplehnlNZEdtgQ@hX0CNeIWEpxw!oyN ndc~tsp9TlidOzOC&-)*|KH)3pD2ngr00000NkvXXu0mjf<KNUz literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable-sm.png b/web/pgadmin/misc/static/explain/img/exttable-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..acd43cb8abab6ef38daf34ff6d7544153a11dacf GIT binary patch literal 612 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47`X#{LR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)^XY$8$A0G@_?f)(TiB-0o~u9DE`4h_ z@3s2Om(8dDdI7mh-fGNz8JxJ$(RuCl>$mUSyLbQo{YQ@;J%0Rn>9T9)mKA9e*Bv-; z!q9k*y7s}c^63vAJOIkOd8|>@*q@f(clYkyWy_XDM0Trbo^<nAscUdhS#3sp`^5F@ z*S~u8DlvJNy7pxi^{qR09)J1r<?Gk4&!4|-WV%sNW#!y?Ya^o8sA?W7EL!yO<Hxse z-}X<~s-}6=(71d4{Dn`SK5cATs;+%VU9<bdiL;%Z6I)tVJ$drv&6_t59=vw<+ErTC zQw{Rh4~>~Gc%JJ_00swRNswPKgTu2MX+REVfk$L9koEv$x0Bg+K*j`57sn8Z%gG4} zOa@Af9Sp+8+}hIC?Ck2|<}MBG)BEEc0z4vIL{>Gq^Qb83DJpS_PM9=p;?&9E0U<$c zTq{<rTA7`ZmHE2Bfwko87hay;9$%lc3z#+)6+IK17IrPoEP&B6+Pa$ET|Heqd_}|T z-R;Y#Z{6O%UOwc2y~2g=!)h89Dk9JL?rkX8V67z4`B96(W2)e}i60vRfNoPQag8WR zNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTd cHGouG8JIydoSGiG2B?9-)78&qol`;+0LVQH?EnA( literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable.png b/web/pgadmin/misc/static/explain/img/exttable.png new file mode 100644 index 0000000000000000000000000000000000000000..5d84035feea62d53d457481178b1bcbe9622f856 GIT binary patch literal 793 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47;6K3LR^7d#i`GGFZ`c${`aEG zUw7Sjd-49u`;VVLefIp>vuC#+K3#L}dGf{=db3}2pa0)_=3m{3Kc$C%<?Q>BxZ_*c zrqAAMJ~%9YXTIQ#?wnU@GhViy`J27(hvTw$W((iw&U_Y~)1HyF{qEhn_wL=hfB*i2 z2M-=TeE8_mqsNaQ8yXiV>iW%}zd>1TV^GL$BjYL^{S(WU9oVt+prXnmSNFZkm#=*C z<jL~o%k>TF^o@>PyZ-vst5*{zPLflcU|_QU>a|B#uU=JF?bJ2cziipY_3PKae*OB& zm8%-sEqaEB)ikG?m>;=w=lPpAZ{EIr`|{<>zP<^HDjPJkuS}Y>_5J(zA3l8e^y$;P zckfoNT)BGn>N#`fDXPqIbUAEeo3EjBs<&_JrcIlkKYzY=?-6CSwcft_U%!6i?2@ga zbAH+K$Dcoc{`&RnzI`WD)Hj5LAKkcd)7Gt9lT#YiwN7;R-um|K+wv9LmDM(Tcy0Rl z@#D5_+u{=nRW-JDc3)AL{8UY|HzVudq)BroPg$ri@$mwIO;dmoz*rLG7tG-B>_!@p z!&%@FSq!8-z}W3%wjGdh+0(@_MB;LCLV^n;4-Zd|&l#OHId5d<%!#>Uvqyo^u8z@B zF;Otku#nSp1DBm9qhscRhMqMtE)H>yfu51Bp}w)6&cZqimabjQ@@VyoS1+4cMR<97 zd#?KUoIRtfbCAhvS=cqRZDrs1`uxr%FfOPQ4>vF8_xIM%-_X$2-@kPI{CbCkfC7#P z2U8Or8zmzxD>XAS4xIy%;`1lWcrs_sq*>GW#5zu&ICF}R^VG?+r}Y`QMZ`qYkF!mE zGG*G-@CFvG)vNY8H+eN(zQmoCbx`Y7z#e{vFBY0Te&TE7f!<Rsag8WRNi0dVN-jzT zQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTdHGouG8JIyd UoSGiG2B?9-)78&qol`;+0Q{<O$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttables.png b/web/pgadmin/misc/static/explain/img/exttables.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dfbd454ed33727bd1deeb87c62f8671f6a5a03 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47^MPyLR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)(1uT&ufDx|_ipp)e^tkR=O6f)yz^Vw zrq7<MKiDpPYdG(<`plR2?%iuX{nra9vgEDdjF%cSU*5le-z{*Hjoqv(SFS&L^yu;9 z$BCh54YV)SY`ps5!GohmFPT|vP}AIAUOws6@q1>vXAHE?^>wU&`SRt%hYy!6TNV*D zT}|t>v;9UL?W?Amt7goYwSN8jSFc`8IQ7}h=Aef5HBHT(=Pz7){rdI(-PetE&Kqf+ zTC?J?x9>_dt@Dk|J3fB=`1bAF+~nQb+SeRSH>_B(;_1_;Rn;?8HFg`BEWUQ_zJ=bg zri$H9o;-Q;=FOu=PwX9+YwPW<2KnxXa>IqjgMEvDp~F}b<QL4~@a#q!ki%Kv5m^kR zJ;2!QWVRiUvDwqbF+}2W?0HwQLk<G27xhdW8XmB4zY~jTVks}b`QPk?8Z+O@ht}mE zxDUR+@ZDiy$V$_wu1ha@gBJAuXUmw$IQdLNWLm+2wv7?FW$l-rva#qG$_eeUt7l;6 zYfsQPQ#3I{XWjwDPG7CLC)J97I!!#j(8XtG(AulgXTzi?C<q+hI5%(o`R%TodS@Ig zFq!9*{+X5YhEDkFv(xUs<#&JSY%y0q+H23fcl??hCZB62%C0l7Vc_x-dugW}eiG<> z)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!XjU}|MxU@=ow4n;$5eoAIq iB}9XPC0GMUwUvPxM8m1+p=*E|7(8A5T-G@yGywoZHZsuw literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/js/snap.svg-min.js b/web/pgadmin/misc/static/explain/js/snap.svg-min.js new file mode 100644 index 0000000..6567d19 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg-min.js @@ -0,0 +1,21 @@ +// Snap.svg 0.4.1 +// +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// build: 2015-04-13 + +!function(a){var b,c,d="0.4.2",e="hasOwnProperty",f=/[\.\/]/,g=/\s*,\s*/,h="*",i=function(a,b){return a-b},j={n:{}},k=function(){for(var a=0,b=this.length;b>a;a++)if("undefined"!=typeof this[a])return this[a]},l=function(){for(var a=this.length;--a;)if("undefined"!=typeof this[a])return this[a]},m=function(a,d){a=String(a);var e,f=c,g=Array.prototype.slice.call(arguments,2),h=m.listeners(a),j=0,n=[],o={},p=[],q=b;p.firstDefined=k,p.lastDefined=l,b=a,c=0;for(var r=0,s=h.length;s>r;r++)"zIndex"in h[r]&&(n.push(h[r].zIndex),h[r].zIndex<0&&(o[h[r].zIndex]=h[r]));for(n.sort(i);n[j]<0;)if(e=o[n[j++]],p.push(e.apply(d,g)),c)return c=f,p;for(r=0;s>r;r++)if(e=h[r],"zIndex"in e)if(e.zIndex==n[j]){if(p.push(e.apply(d,g)),c)break;do if(j++,e=o[n[j]],e&&p.push(e.apply(d,g)),c)break;while(e)}else o[e.zIndex]=e;else if(p.push(e.apply(d,g)),c)break;return c=f,b=q,p};m._events=j,m.listeners=function(a){var b,c,d,e,g,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,g=m.length;g>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[h]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},m.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(g),d=0,e=c.length;e>d;d++)!function(a){for(var c,d=a.split(f),e=j,g=0,h=d.length;h>g;g++)e=e.n,e=e.hasOwnProperty(d[g])&&e[d[g]]||(e[d[g]]={n:{}});for(e.f=e.f||[],g=0,h=e.f.length;h>g;g++)if(e.f[g]==b){c=!0;break}!c&&e.f.push(b)}(c[d]);return function(a){+a==+a&&(b.zIndex=+a)}},m.f=function(a){var b=[].slice.call(arguments,1);return function(){m.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},m.stop=function(){c=1},m.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},m.nts=function(){return b.split(f)},m.off=m.unbind=function(a,b){if(!a)return void(m._events=j={n:{}});var c=a.split(g);if(c.length>1)for(var d=0,i=c.length;i>d;d++)m.off(c[d],b);else{c=a.split(f);var k,l,n,d,i,o,p,q=[j];for(d=0,i=c.length;i>d;d++)for(o=0;o<q.length;o+=n.length-2){if(n=[o,1],k=q[o].n,c[d]!=h)k[c[d]]&&n.push(k[c[d]]);else for(l in k)k[e](l)&&n.push(k[l]);q.splice.apply(q,n)}for(d=0,i=q.length;i>d;d++)for(k=q[d];k.n;){if(b){if(k.f){for(o=0,p=k.f.length;p>o;o++)if(k.f[o]==b){k.f.splice(o,1);break}!k.f.length&&delete k.f}for(l in k.n)if(k.n[e](l)&&k.n[l].f){var r=k.n[l].f;for(o=0,p=r.length;p>o;o++)if(r[o]==b){r.splice(o,1);break}!r.length&&delete k.n[l].f}}else{delete k.f;for(l in k.n)k.n[e](l)&&k.n[l].f&&delete k.n[l].f}k=k.n}}},m.once=function(a,b){var c=function(){return m.unbind(a,c),b.apply(this,arguments)};return m.on(a,c)},m.version=d,m.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=m:"function"==typeof define&&define.amd?define("eve",[],function(){return m}):a.eve=m}(this),function(a,b){if("function"==typeof define&&define.amd)define(["eve"],function(c){return b(a,c)});else if("undefined"!=typeof exports){var c=require("eve");module.exports=b(a,c)}else b(a,a.eve)}(window||this,function(a,b){var c=function(b){var c={},d=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},e=Array.isArray||function(a){return a instanceof Array||"[object Array]"==Object.prototype.toString.call(a)},f=0,g="M"+(+new Date).toString(36),h=function(){return g+(f++).toString(36)},i=Date.now||function(){return+new Date},j=function(a){var b=this;if(null==a)return b.s;var c=b.s-a;b.b+=b.dur*c,b.B+=b.dur*c,b.s=a},k=function(a){var b=this;return null==a?b.spd:void(b.spd=a)},l=function(a){var b=this;return null==a?b.dur:(b.s=b.s*a/b.dur,void(b.dur=a))},m=function(){var a=this;delete c[a.id],a.update(),b("mina.stop."+a.id,a)},n=function(){var a=this;a.pdif||(delete c[a.id],a.update(),a.pdif=a.get()-a.b)},o=function(){var a=this;a.pdif&&(a.b=a.get()-a.pdif,delete a.pdif,c[a.id]=a)},p=function(){var a,b=this;if(e(b.start)){a=[];for(var c=0,d=b.start.length;d>c;c++)a[c]=+b.start[c]+(b.end[c]-b.start[c])*b.easing(b.s)}else a=+b.start+(b.end-b.start)*b.easing(b.s);b.set(a)},q=function(){var a=0;for(var e in c)if(c.hasOwnProperty(e)){var f=c[e],g=f.get();a++,f.s=(g-f.b)/(f.dur/f.spd),f.s>=1&&(delete c[e],f.s=1,a--,function(a){setTimeout(function(){b("mina.finish."+a.id,a)})}(f)),f.update()}a&&d(q)},r=function(a,b,e,f,g,i,s){var t={id:h(),start:a,end:b,b:e,s:0,dur:f-e,spd:1,get:g,set:i,easing:s||r.linear,status:j,speed:k,duration:l,stop:m,pause:n,resume:o,update:p};c[t.id]=t;var u,v=0;for(u in c)if(c.hasOwnProperty(u)&&(v++,2==v))break;return 1==v&&d(q),t};return r.time=i,r.getById=function(a){return c[a]||null},r.linear=function(a){return a},r.easeout=function(a){return Math.pow(a,1.7)},r.easein=function(a){return Math.pow(a,.48)},r.easeinout=function(a){if(1==a)return 1;if(0==a)return 0;var b=.48-a/1.04,c=Math.sqrt(.1734+b*b),d=c-b,e=Math.pow(Math.abs(d),1/3)*(0>d?-1:1),f=-c-b,g=Math.pow(Math.abs(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},r.backin=function(a){if(1==a)return 1;var b=1.70158;return a*a*((b+1)*a-b)},r.backout=function(a){if(0==a)return 0;a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},r.elastic=function(a){return a==!!a?a:Math.pow(2,-10*a)*Math.sin(2*(a-.075)*Math.PI/.3)+1},r.bounce=function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b},a.mina=r,r}("undefined"==typeof b?function(){}:b),d=function(a){function c(a,b){if(a){if(a.nodeType)return w(a);if(e(a,"array")&&c.set)return c.set.apply(c,a);if(a instanceof s)return a;if(null==b)return a=y.doc.querySelector(String(a)),w(a)}return a=null==a?"100%":a,b=null==b?"100%":b,new v(a,b)}function d(a,b){if(b){if("#text"==a&&(a=y.doc.createTextNode(b.text||b["#text"]||"")),"#comment"==a&&(a=y.doc.createComment(b.text||b["#text"]||"")),"string"==typeof a&&(a=d(a)),"string"==typeof b)return 1==a.nodeType?"xlink:"==b.substring(0,6)?a.getAttributeNS(T,b.substring(6)):"xml:"==b.substring(0,4)?a.getAttributeNS(U,b.substring(4)):a.getAttribute(b):"text"==b?a.nodeValue:null;if(1==a.nodeType){for(var c in b)if(b[z](c)){var e=A(b[c]);e?"xlink:"==c.substring(0,6)?a.setAttributeNS(T,c.substring(6),e):"xml:"==c.substring(0,4)?a.setAttributeNS(U,c.substring(4),e):a.setAttribute(c,e):a.removeAttribute(c)}}else"text"in b&&(a.nodeValue=b.text)}else a=y.doc.createElementNS(U,a);return a}function e(a,b){return b=A.prototype.toLowerCase.call(b),"finite"==b?isFinite(a):"array"==b&&(a instanceof Array||Array.isArray&&Array.isArray(a))?!0:"null"==b&&null===a||b==typeof a&&null!==a||"object"==b&&a===Object(a)||J.call(a).slice(8,-1).toLowerCase()==b}function f(a){if("function"==typeof a||Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[z](c)&&(b[c]=f(a[c]));return b}function h(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function i(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),g=d.cache=d.cache||{},i=d.count=d.count||[];return g[z](f)?(h(i,f),c?c(g[f]):g[f]):(i.length>=1e3&&delete g[i.shift()],i.push(f),g[f]=a.apply(b,e),c?c(g[f]):g[f])}return d}function j(a,b,c,d,e,f){if(null==e){var g=a-c,h=b-d;return g||h?(180+180*D.atan2(-h,-g)/H+360)%360:0}return j(a,b,e,f)-j(c,d,e,f)}function k(a){return a%360*H/180}function l(a){return 180*a/H%360}function m(a){var b=[];return a=a.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g,function(a,c,d){return d=d.split(/\s*,\s*|\s+/),"rotate"==c&&1==d.length&&d.push(0,0),"scale"==c&&(d.length>2?d=d.slice(0,2):2==d.length&&d.push(0,0),1==d.length&&d.push(d[0],0,0)),b.push("skewX"==c?["m",1,0,D.tan(k(d[0])),1,0,0]:"skewY"==c?["m",1,D.tan(k(d[0])),0,1,0,0]:[c.charAt(0)].concat(d)),a}),b}function n(a,b){var d=ab(a),e=new c.Matrix;if(d)for(var f=0,g=d.length;g>f;f++){var h,i,j,k,l,m=d[f],n=m.length,o=A(m[0]).toLowerCase(),p=m[0]!=o,q=p?e.invert():0;"t"==o&&2==n?e.translate(m[1],0):"t"==o&&3==n?p?(h=q.x(0,0),i=q.y(0,0),j=q.x(m[1],m[2]),k=q.y(m[1],m[2]),e.translate(j-h,k-i)):e.translate(m[1],m[2]):"r"==o?2==n?(l=l||b,e.rotate(m[1],l.x+l.width/2,l.y+l.height/2)):4==n&&(p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.rotate(m[1],j,k)):e.rotate(m[1],m[2],m[3])):"s"==o?2==n||3==n?(l=l||b,e.scale(m[1],m[n-1],l.x+l.width/2,l.y+l.height/2)):4==n?p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.scale(m[1],m[1],j,k)):e.scale(m[1],m[1],m[2],m[3]):5==n&&(p?(j=q.x(m[3],m[4]),k=q.y(m[3],m[4]),e.scale(m[1],m[2],j,k)):e.scale(m[1],m[2],m[3],m[4])):"m"==o&&7==n&&e.add(m[1],m[2],m[3],m[4],m[5],m[6])}return e}function o(a){var b=a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||a.node.parentNode&&w(a.node.parentNode)||c.select("svg")||c(0,0),d=b.select("defs"),e=null==d?!1:d.node;return e||(e=u("defs",b.node).node),e}function p(a){return a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||c.select("svg")}function q(a,b,c){function e(a){if(null==a)return I;if(a==+a)return a;d(j,{width:a});try{return j.getBBox().width}catch(b){return 0}}function f(a){if(null==a)return I;if(a==+a)return a;d(j,{height:a});try{return j.getBBox().height}catch(b){return 0}}function g(d,e){null==b?i[d]=e(a.attr(d)||0):d==b&&(i=e(null==c?a.attr(d)||0:c))}var h=p(a).node,i={},j=h.querySelector(".svg---mgr");switch(j||(j=d("rect"),d(j,{x:-9e9,y:-9e9,width:10,height:10,"class":"svg---mgr",fill:"none"}),h.appendChild(j)),a.type){case"rect":g("rx",e),g("ry",f);case"image":g("width",e),g("height",f);case"text":g("x",e),g("y",f);break;case"circle":g("cx",e),g("cy",f),g("r",e);break;case"ellipse":g("cx",e),g("cy",f),g("rx",e),g("ry",f);break;case"line":g("x1",e),g("x2",e),g("y1",f),g("y2",f);break;case"marker":g("refX",e),g("markerWidth",e),g("refY",f),g("markerHeight",f);break;case"radialGradient":g("fx",e),g("fy",f);break;case"tspan":g("dx",e),g("dy",f);break;default:g(b,e)}return h.removeChild(j),i}function r(a){e(a,"array")||(a=Array.prototype.slice.call(arguments,0));for(var b=0,c=0,d=this.node;this[b];)delete this[b++];for(b=0;b<a.length;b++)"set"==a[b].type?a[b].forEach(function(a){d.appendChild(a.node)}):d.appendChild(a[b].node);var f=d.childNodes;for(b=0;b<f.length;b++)this[c++]=w(f[b]);return this}function s(a){if(a.snap in V)return V[a.snap];var b;try{b=a.ownerSVGElement}catch(c){}this.node=a,b&&(this.paper=new v(b)),this.type=a.tagName||a.nodeName;var d=this.id=S(this);if(this.anims={},this._={transform:[]},a.snap=d,V[d]=this,"g"==this.type&&(this.add=r),this.type in{g:1,mask:1,pattern:1,symbol:1})for(var e in v.prototype)v.prototype[z](e)&&(this[e]=v.prototype[e])}function t(a){this.node=a}function u(a,b){var c=d(a);b.appendChild(c);var e=w(c);return e}function v(a,b){var c,e,f,g=v.prototype;if(a&&"svg"==a.tagName){if(a.snap in V)return V[a.snap];var h=a.ownerDocument;c=new s(a),e=a.getElementsByTagName("desc")[0],f=a.getElementsByTagName("defs")[0],e||(e=d("desc"),e.appendChild(h.createTextNode("Created with Snap")),c.node.appendChild(e)),f||(f=d("defs"),c.node.appendChild(f)),c.defs=f;for(var i in g)g[z](i)&&(c[i]=g[i]);c.paper=c.root=c}else c=u("svg",y.doc.body),d(c.node,{height:b,version:1.1,width:a,xmlns:U});return c}function w(a){return a?a instanceof s||a instanceof t?a:a.tagName&&"svg"==a.tagName.toLowerCase()?new v(a):a.tagName&&"object"==a.tagName.toLowerCase()&&"image/svg+xml"==a.type?new v(a.contentDocument.getElementsByTagName("svg")[0]):new s(a):a}function x(a,b){for(var c=0,d=a.length;d>c;c++){var e={type:a[c].type,attr:a[c].attr()},f=a[c].children();b.push(e),f.length&&x(f,e.childNodes=[])}}c.version="0.4.0",c.toString=function(){return"Snap v"+this.version},c._={};var y={win:a.window,doc:a.window.document};c._.glob=y;{var z="hasOwnProperty",A=String,B=parseFloat,C=parseInt,D=Math,E=D.max,F=D.min,G=D.abs,H=(D.pow,D.PI),I=(D.round,""),J=Object.prototype.toString,K=/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,L=(c._.separator=/[,\s]+/,/[\s]*,[\s]*/),M={hs:1,rg:1},N=/([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,O=/([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,P=/(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/gi,Q=0,R="S"+(+new Date).toString(36),S=function(a){return(a&&a.type?a.type:I)+R+(Q++).toString(36)},T="http://www.w3.org/1999/xlink",U="http://www.w3.org/2000/svg",V={};c.url=function(a){return"url('#"+a+"')"}}c._.$=d,c._.id=S,c.format=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return A(b).replace(a,function(a,b){return c(a,b,d)})}}(),c._.clone=f,c._.cacher=i,c.rad=k,c.deg=l,c.sin=function(a){return D.sin(c.rad(a))},c.tan=function(a){return D.tan(c.rad(a))},c.cos=function(a){return D.cos(c.rad(a))},c.asin=function(a){return c.deg(D.asin(a))},c.acos=function(a){return c.deg(D.acos(a))},c.atan=function(a){return c.deg(D.atan(a))},c.atan2=function(a){return c.deg(D.atan2(a))},c.angle=j,c.len=function(a,b,d,e){return Math.sqrt(c.len2(a,b,d,e))},c.len2=function(a,b,c,d){return(a-c)*(a-c)+(b-d)*(b-d)},c.closestPoint=function(a,b,c){function d(a){var d=a.x-b,e=a.y-c;return d*d+e*e}for(var e,f,g,h,i=a.node,j=i.getTotalLength(),k=j/i.pathSegList.numberOfItems*.125,l=1/0,m=0;j>=m;m+=k)(h=d(g=i.getPointAtLength(m)))<l&&(e=g,f=m,l=h);for(k*=.5;k>.5;){var n,o,p,q,r,s;(p=f-k)>=0&&(r=d(n=i.getPointAtLength(p)))<l?(e=n,f=p,l=r):(q=f+k)<=j&&(s=d(o=i.getPointAtLength(q)))<l?(e=o,f=q,l=s):k*=.5}return e={x:e.x,y:e.y,length:f,distance:Math.sqrt(l)}},c.is=e,c.snapTo=function(a,b,c){if(c=e(c,"finite")?c:10,e(a,"array")){for(var d=a.length;d--;)if(G(a[d]-b)<=c)return a[d]}else{a=+a;var f=b%a;if(c>f)return b-f;if(f>a-c)return b-f+a}return b},c.getRGB=i(function(a){if(!a||(a=A(a)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};if("none"==a)return{r:-1,g:-1,b:-1,hex:"none",toString:Z};if(!(M[z](a.toLowerCase().substring(0,2))||"#"==a.charAt())&&(a=W(a)),!a)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};var b,d,f,g,h,i,j=a.match(K);return j?(j[2]&&(f=C(j[2].substring(5),16),d=C(j[2].substring(3,5),16),b=C(j[2].substring(1,3),16)),j[3]&&(f=C((h=j[3].charAt(3))+h,16),d=C((h=j[3].charAt(2))+h,16),b=C((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=B(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),f=B(i[2]),"%"==i[2].slice(-1)&&(f*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100)),j[5]?(i=j[5].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsb2rgb(b,d,f,g)):j[6]?(i=j[6].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsl2rgb(b,d,f,g)):(b=F(D.round(b),255),d=F(D.round(d),255),f=F(D.round(f),255),g=F(E(g,0),1),j={r:b,g:d,b:f,toString:Z},j.hex="#"+(16777216|f|d<<8|b<<16).toString(16).slice(1),j.opacity=e(g,"finite")?g:1,j)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z}},c),c.hsb=i(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=i(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=i(function(a,b,c,d){if(e(d,"finite")){var f=D.round;return"rgba("+[f(a),f(b),f(c),+d.toFixed(2)]+")"}return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)});var W=function(a){var b=y.doc.getElementsByTagName("head")[0]||y.doc.getElementsByTagName("svg")[0],c="rgb(255, 0, 0)";return(W=i(function(a){if("red"==a.toLowerCase())return c;b.style.color=c,b.style.color=a;var d=y.doc.defaultView.getComputedStyle(b,I).getPropertyValue("color");return d==c?null:d}))(a)},X=function(){return"hsb("+[this.h,this.s,this.b]+")"},Y=function(){return"hsl("+[this.h,this.s,this.l]+")"},Z=function(){return 1==this.opacity||null==this.opacity?this.hex:"rgba("+[this.r,this.g,this.b,this.opacity]+")"},$=function(a,b,d){if(null==b&&e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&e(a,string)){var f=c.getRGB(a);a=f.r,b=f.g,d=f.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},_=function(a,b,d,f){a=D.round(255*a),b=D.round(255*b),d=D.round(255*d);var g={r:a,g:b,b:d,opacity:e(f,"finite")?f:1,hex:c.rgb(a,b,d),toString:Z};return e(f,"finite")&&(g.opacity=f),g};c.color=function(a){var b;return e(a,"object")&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):e(a,"object")&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):(e(a,"string")&&(a=c.getRGB(a)),e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&!("error"in a)?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:"none"},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1,a.error=1)),a.toString=Z,a},c.hsb2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,d=a.o,a=a.h),a*=360;var f,g,h,i,j;return a=a%360/60,j=c*b,i=j*(1-G(a%2-1)),f=g=h=c-j,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.hsl2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var f,g,h,i,j;return a=a%360/60,j=2*b*(.5>c?c:1-c),i=j*(1-G(a%2-1)),f=g=h=c-j/2,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.rgb2hsb=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=E(a,b,c),g=f-F(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:X}},c.rgb2hsl=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=E(a,b,c),h=F(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:Y}},c.parsePathString=function(a){if(!a)return null;var b=c.path(a);if(b.arr)return c.path.clone(b.arr);var d={a:7,c:6,o:2,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,u:3,z:0},f=[];return e(a,"array")&&e(a[0],"array")&&(f=c.path.clone(a)),f.length||A(a).replace(N,function(a,b,c){var e=[],g=b.toLowerCase();if(c.replace(P,function(a,b){b&&e.push(+b)}),"m"==g&&e.length>2&&(f.push([b].concat(e.splice(0,2))),g="l",b="m"==b?"l":"L"),"o"==g&&1==e.length&&f.push([b,e[0]]),"r"==g)f.push([b].concat(e));else for(;e.length>=d[g]&&(f.push([b].concat(e.splice(0,d[g]))),d[g]););}),f.toString=c.path.toString,b.arr=c.path.clone(f),f};var ab=c.parseTransformString=function(a){if(!a)return null;var b=[];return e(a,"array")&&e(a[0],"array")&&(b=c.path.clone(a)),b.length||A(a).replace(O,function(a,c,d){{var e=[];c.toLowerCase()}d.replace(P,function(a,b){b&&e.push(+b)}),b.push([c].concat(e))}),b.toString=c.path.toString,b};c._.svgTransform2string=m,c._.rgTransform=/^[a-z][\s]*-?\.?\d/i,c._.transform2matrix=n,c._unit2px=q;y.doc.contains||y.doc.compareDocumentPosition?function(a,b){var c=9==a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a==d||!(!d||1!=d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b;)if(b=b.parentNode,b==a)return!0;return!1};c._.getSomeDefs=o,c._.getSomeSVG=p,c.select=function(a){return a=A(a).replace(/([^\\]):/g,"$1\\:"),w(y.doc.querySelector(a))},c.selectAll=function(a){for(var b=y.doc.querySelectorAll(a),d=(c.set||Array)(),e=0;e<b.length;e++)d.push(w(b[e]));return d},setInterval(function(){for(var a in V)if(V[z](a)){var b=V[a],c=b.node;("svg"!=b.type&&!c.ownerSVGElement||"svg"==b.type&&(!c.parentNode||"ownerSVGElement"in c.parentNode&&!c.ownerSVGElement))&&delete V[a]}},1e4),s.prototype.attr=function(a,c){var d=this,f=d.node;if(!a){if(1!=f.nodeType)return{text:f.nodeValue};for(var g=f.attributes,h={},i=0,j=g.length;j>i;i++)h[g[i].nodeName]=g[i].nodeValue;return h}if(e(a,"string")){if(!(arguments.length>1))return b("snap.util.getattr."+a,d).firstDefined();var k={};k[a]=c,a=k}for(var l in a)a[z](l)&&b("snap.util.attr."+l,d,a[l]);return d},c.parse=function(a){var b=y.doc.createDocumentFragment(),c=!0,d=y.doc.createElement("div");if(a=A(a),a.match(/^\s*<\s*svg(?:\s|>)/)||(a="<svg>"+a+"</svg>",c=!1),d.innerHTML=a,a=d.getElementsByTagName("svg")[0])if(c)b=a;else for(;a.firstChild;)b.appendChild(a.firstChild);return new t(b)},c.fragment=function(){for(var a=Array.prototype.slice.call(arguments,0),b=y.doc.createDocumentFragment(),d=0,e=a.length;e>d;d++){var f=a[d];f.node&&f.node.nodeType&&b.appendChild(f.node),f.nodeType&&b.appendChild(f),"string"==typeof f&&b.appendChild(c.parse(f).node)}return new t(b)},c._.make=u,c._.wrap=w,v.prototype.el=function(a,b){var c=u(a,this.node);return b&&c.attr(b),c},s.prototype.children=function(){for(var a=[],b=this.node.childNodes,d=0,e=b.length;e>d;d++)a[d]=c(b[d]);return a},s.prototype.toJSON=function(){var a=[];return x([this],a),a[0]},b.on("snap.util.getattr",function(){var a=b.nt();a=a.substring(a.lastIndexOf(".")+1);var c=a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});return bb[z](c)?this.node.ownerDocument.defaultView.getComputedStyle(this.node,null).getPropertyValue(c):d(this.node,a)});var bb={"alignment-baseline":0,"baseline-shift":0,clip:0,"clip-path":0,"clip-rule":0,color:0,"color-interpolation":0,"color-interpolation-filters":0,"color-profile":0,"color-rendering":0,cursor:0,direction:0,display:0,"dominant-baseline":0,"enable-background":0,fill:0,"fill-opacity":0,"fill-rule":0,filter:0,"flood-color":0,"flood-opacity":0,font:0,"font-family":0,"font-size":0,"font-size-adjust":0,"font-stretch":0,"font-style":0,"font-variant":0,"font-weight":0,"glyph-orientation-horizontal":0,"glyph-orientation-vertical":0,"image-rendering":0,kerning:0,"letter-spacing":0,"lighting-color":0,marker:0,"marker-end":0,"marker-mid":0,"marker-start":0,mask:0,opacity:0,overflow:0,"pointer-events":0,"shape-rendering":0,"stop-color":0,"stop-opacity":0,stroke:0,"stroke-dasharray":0,"stroke-dashoffset":0,"stroke-linecap":0,"stroke-linejoin":0,"stroke-miterlimit":0,"stroke-opacity":0,"stroke-width":0,"text-anchor":0,"text-decoration":0,"text-rendering":0,"unicode-bidi":0,visibility:0,"word-spacing":0,"writing-mode":0};b.on("snap.util.attr",function(a){var c=b.nt(),e={};c=c.substring(c.lastIndexOf(".")+1),e[c]=a;var f=c.replace(/-(\w)/gi,function(a,b){return b.toUpperCase()}),g=c.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});bb[z](g)?this.node.style[f]=null==a?I:a:d(this.node,e)}),function(){}(v.prototype),c.ajax=function(a,c,d,f){var g=new XMLHttpRequest,h=S();if(g){if(e(c,"function"))f=d,d=c,c=null;else if(e(c,"object")){var i=[];for(var j in c)c.hasOwnProperty(j)&&i.push(encodeURIComponent(j)+"="+encodeURIComponent(c[j]));c=i.join("&")}return g.open(c?"POST":"GET",a,!0),c&&(g.setRequestHeader("X-Requested-With","XMLHttpRequest"),g.setRequestHeader("Content-type","application/x-www-form-urlencoded")),d&&(b.once("snap.ajax."+h+".0",d),b.once("snap.ajax."+h+".200",d),b.once("snap.ajax."+h+".304",d)),g.onreadystatechange=function(){4==g.readyState&&b("snap.ajax."+h+"."+g.status,f,g)},4==g.readyState?g:(g.send(c),g)}},c.load=function(a,b,d){c.ajax(a,function(a){var e=c.parse(a.responseText);d?b.call(d,e):b(e)})};var cb=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,h=e.clientLeft||d.clientLeft||0,i=b.top+(g.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(g.win.pageXOffset||e.scrollLeft||d.scrollLeft)-h;return{y:i,x:j}};return c.getElementByPoint=function(a,b){var c=this,d=(c.canvas,y.doc.elementFromPoint(a,b));if(y.win.opera&&"svg"==d.tagName){var e=cb(d),f=d.createSVGRect();f.x=a-e.x,f.y=b-e.y,f.width=f.height=1;var g=d.getIntersectionList(f,null);g.length&&(d=g[g.length-1])}return d?w(d):null},c.plugin=function(a){a(c,s,v,y,t)},y.win.Snap=c,c}(a||this);return d.plugin(function(d,e,f,g,h){function i(a,b){if(null==b){var c=!0;if(b=a.node.getAttribute("linearGradient"==a.type||"radialGradient"==a.type?"gradientTransform":"pattern"==a.type?"patternTransform":"transform"),!b)return new d.Matrix;b=d._.svgTransform2string(b)}else b=d._.rgTransform.test(b)?o(b).replace(/\.{3}|\u2026/g,a._.transform||""):d._.svgTransform2string(b),n(b,"array")&&(b=d.path?d.path.toString.call(b):o(b)),a._.transform=b;var e=d._.transform2matrix(b,a.getBBox(1));return c?e:void(a.matrix=e)}function j(a){function b(a,b){var c=q(a.node,b);c=c&&c.match(f),c=c&&c[2],c&&"#"==c.charAt()&&(c=c.substring(1),c&&(h[c]=(h[c]||[]).concat(function(c){var d={};d[b]=URL(c),q(a.node,d)})))}function c(a){var b=q(a.node,"xlink:href");b&&"#"==b.charAt()&&(b=b.substring(1),b&&(h[b]=(h[b]||[]).concat(function(b){a.attr("xlink:href","#"+b)})))}for(var d,e=a.selectAll("*"),f=/^\s*url\(("|'|)(.*)\1\)\s*$/,g=[],h={},i=0,j=e.length;j>i;i++){d=e[i],b(d,"fill"),b(d,"stroke"),b(d,"filter"),b(d,"mask"),b(d,"clip-path"),c(d);var k=q(d.node,"id");k&&(q(d.node,{id:d.id}),g.push({old:k,id:d.id}))}for(i=0,j=g.length;j>i;i++){var l=h[g[i].old];if(l)for(var m=0,n=l.length;n>m;m++)l[m](g[i].id)}}function k(a,b,c){return function(d){var e=d.slice(a,b);return 1==e.length&&(e=e[0]),c?c(e):e}}function l(a){return function(){var b=a?"<"+this.type:"",c=this.node.attributes,d=this.node.childNodes;if(a)for(var e=0,f=c.length;f>e;e++)b+=" "+c[e].name+'="'+c[e].value.replace(/"/g,'\\"')+'"';if(d.length){for(a&&(b+=">"),e=0,f=d.length;f>e;e++)3==d[e].nodeType?b+=d[e].nodeValue:1==d[e].nodeType&&(b+=u(d[e]).toString());a&&(b+="</"+this.type+">")}else a&&(b+="/>");return b}}var m=e.prototype,n=d.is,o=String,p=d._unit2px,q=d._.$,r=d._.make,s=d._.getSomeDefs,t="hasOwnProperty",u=d._.wrap;m.getBBox=function(a){if(!d.Matrix||!d.path)return this.node.getBBox();var b=this,c=new d.Matrix;if(b.removed)return d._.box();for(;"use"==b.type;)if(a||(c=c.add(b.transform().localMatrix.translate(b.attr("x")||0,b.attr("y")||0))),b.original)b=b.original;else{var e=b.attr("xlink:href");b=b.original=b.node.ownerDocument.getElementById(e.substring(e.indexOf("#")+1))}var f=b._,g=d.path.get[b.type]||d.path.get.deflt;try{return a?(f.bboxwt=g?d.path.getBBox(b.realPath=g(b)):d._.box(b.node.getBBox()),d._.box(f.bboxwt)):(b.realPath=g(b),b.matrix=b.transform().localMatrix,f.bbox=d.path.getBBox(d.path.map(b.realPath,c.add(b.matrix))),d._.box(f.bbox))}catch(h){return d._.box()}};var v=function(){return this.string};m.transform=function(a){var b=this._;if(null==a){for(var c,e=this,f=new d.Matrix(this.node.getCTM()),g=i(this),h=[g],j=new d.Matrix,k=g.toTransformString(),l=o(g)==o(this.matrix)?o(b.transform):k;"svg"!=e.type&&(e=e.parent());)h.push(i(e));for(c=h.length;c--;)j.add(h[c]);return{string:l,globalMatrix:f,totalMatrix:j,localMatrix:g,diffMatrix:f.clone().add(g.invert()),global:f.toTransformString(),total:j.toTransformString(),local:k,toString:v}}return a instanceof d.Matrix?(this.matrix=a,this._.transform=a.toTransformString()):i(this,a),this.node&&("linearGradient"==this.type||"radialGradient"==this.type?q(this.node,{gradientTransform:this.matrix}):"pattern"==this.type?q(this.node,{patternTransform:this.matrix}):q(this.node,{transform:this.matrix})),this},m.parent=function(){return u(this.node.parentNode)},m.append=m.add=function(a){if(a){if("set"==a.type){var b=this;return a.forEach(function(a){b.add(a)}),this}a=u(a),this.node.appendChild(a.node),a.paper=this.paper}return this},m.appendTo=function(a){return a&&(a=u(a),a.append(this)),this},m.prepend=function(a){if(a){if("set"==a.type){var b,c=this;return a.forEach(function(a){b?b.after(a):c.prepend(a),b=a}),this}a=u(a);var d=a.parent();this.node.insertBefore(a.node,this.node.firstChild),this.add&&this.add(),a.paper=this.paper,this.parent()&&this.parent().add(),d&&d.add()}return this},m.prependTo=function(a){return a=u(a),a.prepend(this),this},m.before=function(a){if("set"==a.type){var b=this;return a.forEach(function(a){var c=a.parent();b.node.parentNode.insertBefore(a.node,b.node),c&&c.add()}),this.parent().add(),this}a=u(a);var c=a.parent();return this.node.parentNode.insertBefore(a.node,this.node),this.parent()&&this.parent().add(),c&&c.add(),a.paper=this.paper,this},m.after=function(a){a=u(a);var b=a.parent();return this.node.nextSibling?this.node.parentNode.insertBefore(a.node,this.node.nextSibling):this.node.parentNode.appendChild(a.node),this.parent()&&this.parent().add(),b&&b.add(),a.paper=this.paper,this},m.insertBefore=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.insertAfter=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node.nextSibling),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.remove=function(){var a=this.parent();return this.node.parentNode&&this.node.parentNode.removeChild(this.node),delete this.paper,this.removed=!0,a&&a.add(),this},m.select=function(a){return u(this.node.querySelector(a))},m.selectAll=function(a){for(var b=this.node.querySelectorAll(a),c=(d.set||Array)(),e=0;e<b.length;e++)c.push(u(b[e]));return c},m.asPX=function(a,b){return null==b&&(b=this.attr(a)),+p(this,a,b)},m.use=function(){var a,b=this.node.id;return b||(b=this.id,q(this.node,{id:b})),a="linearGradient"==this.type||"radialGradient"==this.type||"pattern"==this.type?r(this.type,this.node.parentNode):r("use",this.node.parentNode),q(a.node,{"xlink:href":"#"+b}),a.original=this,a},m.clone=function(){var a=u(this.node.cloneNode(!0));return q(a.node,"id")&&q(a.node,{id:a.id}),j(a),a.insertAfter(this),a},m.toDefs=function(){var a=s(this);return a.appendChild(this.node),this},m.pattern=m.toPattern=function(a,b,c,d){var e=r("pattern",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,a=a.x),q(e.node,{x:a,y:b,width:c,height:d,patternUnits:"userSpaceOnUse",id:e.id,viewBox:[a,b,c,d].join(" ")}),e.node.appendChild(this.node),e},m.marker=function(a,b,c,d,e,f){var g=r("marker",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,e=a.refX||a.cx,f=a.refY||a.cy,a=a.x),q(g.node,{viewBox:[a,b,c,d].join(" "),markerWidth:c,markerHeight:d,orient:"auto",refX:e||0,refY:f||0,id:g.id}),g.node.appendChild(this.node),g};var w=function(a,b,d,e){"function"!=typeof d||d.length||(e=d,d=c.linear),this.attr=a,this.dur=b,d&&(this.easing=d),e&&(this.callback=e)};d._.Animation=w,d.animation=function(a,b,c,d){return new w(a,b,c,d)},m.inAnim=function(){var a=this,b=[];for(var c in a.anims)a.anims[t](c)&&!function(a){b.push({anim:new w(a._attrs,a.dur,a.easing,a._callback),mina:a,curStatus:a.status(),status:function(b){return a.status(b)},stop:function(){a.stop()}})}(a.anims[c]);return b},d.animate=function(a,d,e,f,g,h){"function"!=typeof g||g.length||(h=g,g=c.linear);var i=c.time(),j=c(a,d,i,i+f,c.time,e,g);return h&&b.once("mina.finish."+j.id,h),j},m.stop=function(){for(var a=this.inAnim(),b=0,c=a.length;c>b;b++)a[b].stop();return this},m.animate=function(a,d,e,f){"function"!=typeof e||e.length||(f=e,e=c.linear),a instanceof w&&(f=a.callback,e=a.easing,d=a.dur,a=a.attr);var g,h,i,j,l=[],m=[],p={},q=this;for(var r in a)if(a[t](r)){q.equal?(j=q.equal(r,o(a[r])),g=j.from,h=j.to,i=j.f):(g=+q.attr(r),h=+a[r]);var s=n(g,"array")?g.length:1;p[r]=k(l.length,l.length+s,i),l=l.concat(g),m=m.concat(h)}var u=c.time(),v=c(l,m,u,u+d,c.time,function(a){var b={};for(var c in p)p[t](c)&&(b[c]=p[c](a));q.attr(b)},e);return q.anims[v.id]=v,v._attrs=a,v._callback=f,b("snap.animcreated."+q.id,v),b.once("mina.finish."+v.id,function(){delete q.anims[v.id],f&&f.call(q)}),b.once("mina.stop."+v.id,function(){delete q.anims[v.id]}),q};var x={};m.data=function(a,c){var e=x[this.id]=x[this.id]||{};if(0==arguments.length)return b("snap.data.get."+this.id,this,e,null),e; +if(1==arguments.length){if(d.is(a,"object")){for(var f in a)a[t](f)&&this.data(f,a[f]);return this}return b("snap.data.get."+this.id,this,e[a],a),e[a]}return e[a]=c,b("snap.data.set."+this.id,this,c,a),this},m.removeData=function(a){return null==a?x[this.id]={}:x[this.id]&&delete x[this.id][a],this},m.outerSVG=m.toString=l(1),m.innerSVG=l(),m.toDataURL=function(){if(a&&a.btoa){var b=this.getBBox(),c=d.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>',{x:+b.x.toFixed(3),y:+b.y.toFixed(3),width:+b.width.toFixed(3),height:+b.height.toFixed(3),contents:this.outerSVG()});return"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(c)))}},h.prototype.select=m.select,h.prototype.selectAll=m.selectAll}),d.plugin(function(a){function b(a,b,d,e,f,g){return null==b&&"[object SVGMatrix]"==c.call(a)?(this.a=a.a,this.b=a.b,this.c=a.c,this.d=a.d,this.e=a.e,void(this.f=a.f)):void(null!=a?(this.a=+a,this.b=+b,this.c=+d,this.d=+e,this.e=+f,this.f=+g):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0))}var c=Object.prototype.toString,d=String,e=Math,f="";!function(c){function g(a){return a[0]*a[0]+a[1]*a[1]}function h(a){var b=e.sqrt(g(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}c.add=function(a,c,d,e,f,g){var h,i,j,k,l=[[],[],[]],m=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],n=[[a,d,f],[c,e,g],[0,0,1]];for(a&&a instanceof b&&(n=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),h=0;3>h;h++)for(i=0;3>i;i++){for(k=0,j=0;3>j;j++)k+=m[h][j]*n[j][i];l[h][i]=k}return this.a=l[0][0],this.b=l[1][0],this.c=l[0][1],this.d=l[1][1],this.e=l[0][2],this.f=l[1][2],this},c.invert=function(){var a=this,c=a.a*a.d-a.b*a.c;return new b(a.d/c,-a.b/c,-a.c/c,a.a/c,(a.c*a.f-a.d*a.e)/c,(a.b*a.e-a.a*a.f)/c)},c.clone=function(){return new b(this.a,this.b,this.c,this.d,this.e,this.f)},c.translate=function(a,b){return this.add(1,0,0,1,a,b)},c.scale=function(a,b,c,d){return null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d),this},c.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var f=+e.cos(b).toFixed(9),g=+e.sin(b).toFixed(9);return this.add(f,g,-g,f,c,d),this.add(1,0,0,1,-c,-d)},c.x=function(a,b){return a*this.a+b*this.c+this.e},c.y=function(a,b){return a*this.b+b*this.d+this.f},c.get=function(a){return+this[d.fromCharCode(97+a)].toFixed(4)},c.toString=function(){return"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")"},c.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},c.determinant=function(){return this.a*this.d-this.b*this.c},c.split=function(){var b={};b.dx=this.e,b.dy=this.f;var c=[[this.a,this.c],[this.b,this.d]];b.scalex=e.sqrt(g(c[0])),h(c[0]),b.shear=c[0][0]*c[1][0]+c[0][1]*c[1][1],c[1]=[c[1][0]-c[0][0]*b.shear,c[1][1]-c[0][1]*b.shear],b.scaley=e.sqrt(g(c[1])),h(c[1]),b.shear/=b.scaley,this.determinant()<0&&(b.scalex=-b.scalex);var d=-c[0][1],f=c[1][1];return 0>f?(b.rotate=a.deg(e.acos(f)),0>d&&(b.rotate=360-b.rotate)):b.rotate=a.deg(e.asin(d)),b.isSimple=!(+b.shear.toFixed(9)||b.scalex.toFixed(9)!=b.scaley.toFixed(9)&&b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate,b},c.toTransformString=function(a){var b=a||this.split();return+b.shear.toFixed(9)?"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]:(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[+b.dx.toFixed(4),+b.dy.toFixed(4)]:f)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:f)+(b.rotate?"r"+[+b.rotate.toFixed(4),0,0]:f))}}(b.prototype),a.Matrix=b,a.matrix=function(a,c,d,e,f,g){return new b(a,c,d,e,f,g)}}),d.plugin(function(a,c,d,e,f){function g(d){return function(e){if(b.stop(),e instanceof f&&1==e.node.childNodes.length&&("radialGradient"==e.node.firstChild.tagName||"linearGradient"==e.node.firstChild.tagName||"pattern"==e.node.firstChild.tagName)&&(e=e.node.firstChild,n(this).appendChild(e),e=l(e)),e instanceof c)if("radialGradient"==e.type||"linearGradient"==e.type||"pattern"==e.type){e.node.id||p(e.node,{id:e.id});var g=q(e.node.id)}else g=e.attr(d);else if(g=a.color(e),g.error){var h=a(n(this).ownerSVGElement).gradient(e);h?(h.node.id||p(h.node,{id:h.id}),g=q(h.node.id)):g=e}else g=r(g);var i={};i[d]=g,p(this.node,i),this.node.style[d]=t}}function h(a){b.stop(),a==+a&&(a+="px"),this.node.style.fontSize=a}function i(a){for(var b=[],c=a.childNodes,d=0,e=c.length;e>d;d++){var f=c[d];3==f.nodeType&&b.push(f.nodeValue),"tspan"==f.tagName&&b.push(1==f.childNodes.length&&3==f.firstChild.nodeType?f.firstChild.nodeValue:i(f))}return b}function j(){return b.stop(),this.node.style.fontSize}var k=a._.make,l=a._.wrap,m=a.is,n=a._.getSomeDefs,o=/^url\(#?([^)]+)\)$/,p=a._.$,q=a.url,r=String,s=a._.separator,t="";b.on("snap.util.attr.mask",function(a){if(a instanceof c||a instanceof f){if(b.stop(),a instanceof f&&1==a.node.childNodes.length&&(a=a.node.firstChild,n(this).appendChild(a),a=l(a)),"mask"==a.type)var d=a;else d=k("mask",n(this)),d.node.appendChild(a.node);!d.node.id&&p(d.node,{id:d.id}),p(this.node,{mask:q(d.id)})}}),function(a){b.on("snap.util.attr.clip",a),b.on("snap.util.attr.clip-path",a),b.on("snap.util.attr.clipPath",a)}(function(a){if(a instanceof c||a instanceof f){if(b.stop(),"clipPath"==a.type)var d=a;else d=k("clipPath",n(this)),d.node.appendChild(a.node),!d.node.id&&p(d.node,{id:d.id});p(this.node,{"clip-path":q(d.node.id||d.id)})}}),b.on("snap.util.attr.fill",g("fill")),b.on("snap.util.attr.stroke",g("stroke"));var u=/^([lr])(?:\(([^)]*)\))?(.*)$/i;b.on("snap.util.grad.parse",function(a){a=r(a);var b=a.match(u);if(!b)return null;var c=b[1],d=b[2],e=b[3];return d=d.split(/\s*,\s*/).map(function(a){return+a==a?+a:a}),1==d.length&&0==d[0]&&(d=[]),e=e.split("-"),e=e.map(function(a){a=a.split(":");var b={color:a[0]};return a[1]&&(b.offset=parseFloat(a[1])),b}),{type:c,params:d,stops:e}}),b.on("snap.util.attr.d",function(c){b.stop(),m(c,"array")&&m(c[0],"array")&&(c=a.path.toString.call(c)),c=r(c),c.match(/[ruo]/i)&&(c=a.path.toAbsolute(c)),p(this.node,{d:c})})(-1),b.on("snap.util.attr.#text",function(a){b.stop(),a=r(a);for(var c=e.doc.createTextNode(a);this.node.firstChild;)this.node.removeChild(this.node.firstChild);this.node.appendChild(c)})(-1),b.on("snap.util.attr.path",function(a){b.stop(),this.attr({d:a})})(-1),b.on("snap.util.attr.class",function(a){b.stop(),this.node.className.baseVal=a})(-1),b.on("snap.util.attr.viewBox",function(a){var c;c=m(a,"object")&&"x"in a?[a.x,a.y,a.width,a.height].join(" "):m(a,"array")?a.join(" "):a,p(this.node,{viewBox:c}),b.stop()})(-1),b.on("snap.util.attr.transform",function(a){this.transform(a),b.stop()})(-1),b.on("snap.util.attr.r",function(a){"rect"==this.type&&(b.stop(),p(this.node,{rx:a,ry:a}))})(-1),b.on("snap.util.attr.textpath",function(a){if(b.stop(),"text"==this.type){var d,e,f;if(!a&&this.textPath){for(e=this.textPath;e.node.firstChild;)this.node.appendChild(e.node.firstChild);return e.remove(),void delete this.textPath}if(m(a,"string")){var g=n(this),h=l(g.parentNode).path(a);g.appendChild(h.node),d=h.id,h.attr({id:d})}else a=l(a),a instanceof c&&(d=a.attr("id"),d||(d=a.id,a.attr({id:d})));if(d)if(e=this.textPath,f=this.node,e)e.attr({"xlink:href":"#"+d});else{for(e=p("textPath",{"xlink:href":"#"+d});f.firstChild;)e.appendChild(f.firstChild);f.appendChild(e),this.textPath=l(e)}}})(-1),b.on("snap.util.attr.text",function(a){if("text"==this.type){for(var c=this.node,d=function(a){var b=p("tspan");if(m(a,"array"))for(var c=0;c<a.length;c++)b.appendChild(d(a[c]));else b.appendChild(e.doc.createTextNode(a));return b.normalize&&b.normalize(),b};c.firstChild;)c.removeChild(c.firstChild);for(var f=d(a);f.firstChild;)c.appendChild(f.firstChild)}b.stop()})(-1),b.on("snap.util.attr.fontSize",h)(-1),b.on("snap.util.attr.font-size",h)(-1),b.on("snap.util.getattr.transform",function(){return b.stop(),this.transform()})(-1),b.on("snap.util.getattr.textpath",function(){return b.stop(),this.textPath})(-1),function(){function c(c){return function(){b.stop();var d=e.doc.defaultView.getComputedStyle(this.node,null).getPropertyValue("marker-"+c);return"none"==d?d:a(e.doc.getElementById(d.match(o)[1]))}}function d(a){return function(c){b.stop();var d="marker"+a.charAt(0).toUpperCase()+a.substring(1);if(""==c||!c)return void(this.node.style[d]="none");if("marker"==c.type){var e=c.node.id;return e||p(c.node,{id:c.id}),void(this.node.style[d]=q(e))}}}b.on("snap.util.getattr.marker-end",c("end"))(-1),b.on("snap.util.getattr.markerEnd",c("end"))(-1),b.on("snap.util.getattr.marker-start",c("start"))(-1),b.on("snap.util.getattr.markerStart",c("start"))(-1),b.on("snap.util.getattr.marker-mid",c("mid"))(-1),b.on("snap.util.getattr.markerMid",c("mid"))(-1),b.on("snap.util.attr.marker-end",d("end"))(-1),b.on("snap.util.attr.markerEnd",d("end"))(-1),b.on("snap.util.attr.marker-start",d("start"))(-1),b.on("snap.util.attr.markerStart",d("start"))(-1),b.on("snap.util.attr.marker-mid",d("mid"))(-1),b.on("snap.util.attr.markerMid",d("mid"))(-1)}(),b.on("snap.util.getattr.r",function(){return"rect"==this.type&&p(this.node,"rx")==p(this.node,"ry")?(b.stop(),p(this.node,"rx")):void 0})(-1),b.on("snap.util.getattr.text",function(){if("text"==this.type||"tspan"==this.type){b.stop();var a=i(this.node);return 1==a.length?a[0]:a}})(-1),b.on("snap.util.getattr.#text",function(){return this.node.textContent})(-1),b.on("snap.util.getattr.viewBox",function(){b.stop();var c=p(this.node,"viewBox");return c?(c=c.split(s),a._.box(+c[0],+c[1],+c[2],+c[3])):void 0})(-1),b.on("snap.util.getattr.points",function(){var a=p(this.node,"points");return b.stop(),a?a.split(s):void 0})(-1),b.on("snap.util.getattr.path",function(){var a=p(this.node,"d");return b.stop(),a})(-1),b.on("snap.util.getattr.class",function(){return this.node.className.baseVal})(-1),b.on("snap.util.getattr.fontSize",j)(-1),b.on("snap.util.getattr.font-size",j)(-1)}),d.plugin(function(a,b){var c=/\S+/g,d=String,e=b.prototype;e.addClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(h.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e||k.push(f);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.removeClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(k.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e&&k.splice(e,1);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.hasClass=function(a){var b=this.node,d=b.className.baseVal,e=d.match(c)||[];return!!~e.indexOf(a)},e.toggleClass=function(a,b){if(null!=b)return b?this.addClass(a):this.removeClass(a);var d,e,f,g,h=(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];for(d=0;f=h[d++];)e=k.indexOf(f),~e?k.splice(e,1):k.push(f);return g=k.join(" "),j!=g&&(i.className.baseVal=g),this}}),d.plugin(function(){function a(a){return a}function c(a){return function(b){return+b.toFixed(3)+a}}var d={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"/":function(a,b){return a/b},"*":function(a,b){return a*b}},e=String,f=/[a-z]+$/i,g=/^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;b.on("snap.util.attr",function(a){var c=e(a).match(g);if(c){var h=b.nt(),i=h.substring(h.lastIndexOf(".")+1),j=this.attr(i),k={};b.stop();var l=c[3]||"",m=j.match(f),n=d[c[1]];if(m&&m==l?a=n(parseFloat(j),+c[2]):(j=this.asPX(i),a=n(this.asPX(i),this.asPX(i,c[2]+l))),isNaN(j)||isNaN(a))return;k[i]=a,this.attr(k)}})(-10),b.on("snap.util.equal",function(h,i){var j=e(this.attr(h)||""),k=e(i).match(g);if(k){b.stop();var l=k[3]||"",m=j.match(f),n=d[k[1]];return m&&m==l?{from:parseFloat(j),to:n(parseFloat(j),+k[2]),f:c(m)}:(j=this.asPX(h),{from:j,to:n(j,this.asPX(h,k[2]+l)),f:a})}})(-10)}),d.plugin(function(c,d,e,f){var g=e.prototype,h=c.is;g.rect=function(a,b,c,d,e,f){var g;return null==f&&(f=e),h(a,"object")&&"[object Object]"==a?g=a:null!=a&&(g={x:a,y:b,width:c,height:d},null!=e&&(g.rx=e,g.ry=f)),this.el("rect",g)},g.circle=function(a,b,c){var d;return h(a,"object")&&"[object Object]"==a?d=a:null!=a&&(d={cx:a,cy:b,r:c}),this.el("circle",d)};var i=function(){function a(){this.parentNode.removeChild(this)}return function(b,c){var d=f.doc.createElement("img"),e=f.doc.body;d.style.cssText="position:absolute;left:-9999em;top:-9999em",d.onload=function(){c.call(d),d.onload=d.onerror=null,e.removeChild(d)},d.onerror=a,e.appendChild(d),d.src=b}}();g.image=function(a,b,d,e,f){var g=this.el("image");if(h(a,"object")&&"src"in a)g.attr(a);else if(null!=a){var j={"xlink:href":a,preserveAspectRatio:"none"};null!=b&&null!=d&&(j.x=b,j.y=d),null!=e&&null!=f?(j.width=e,j.height=f):i(a,function(){c._.$(g.node,{width:this.offsetWidth,height:this.offsetHeight})}),c._.$(g.node,j)}return g},g.ellipse=function(a,b,c,d){var e;return h(a,"object")&&"[object Object]"==a?e=a:null!=a&&(e={cx:a,cy:b,rx:c,ry:d}),this.el("ellipse",e)},g.path=function(a){var b;return h(a,"object")&&!h(a,"array")?b=a:a&&(b={d:a}),this.el("path",b)},g.group=g.g=function(a){var b=this.el("g");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.svg=function(a,b,c,d,e,f,g,i){var j={};return h(a,"object")&&null==b?j=a:(null!=a&&(j.x=a),null!=b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),null!=e&&null!=f&&null!=g&&null!=i&&(j.viewBox=[e,f,g,i])),this.el("svg",j)},g.mask=function(a){var b=this.el("mask");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.ptrn=function(a,b,c,d,e,f,g,i){if(h(a,"object"))var j=a;else j={patternUnits:"userSpaceOnUse"},a&&(j.x=a),b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),j.viewBox=null!=e&&null!=f&&null!=g&&null!=i?[e,f,g,i]:[a||0,b||0,c||0,d||0];return this.el("pattern",j)},g.use=function(a){return null!=a?(a instanceof d&&(a.attr("id")||a.attr({id:c._.id(a)}),a=a.attr("id")),"#"==String(a).charAt()&&(a=a.substring(1)),this.el("use",{"xlink:href":"#"+a})):d.prototype.use.call(this)},g.symbol=function(a,b,c,d){var e={};return null!=a&&null!=b&&null!=c&&null!=d&&(e.viewBox=[a,b,c,d]),this.el("symbol",e)},g.text=function(a,b,c){var d={};return h(a,"object")?d=a:null!=a&&(d={x:a,y:b,text:c||""}),this.el("text",d)},g.line=function(a,b,c,d){var e={};return h(a,"object")?e=a:null!=a&&(e={x1:a,x2:c,y1:b,y2:d}),this.el("line",e)},g.polyline=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polyline",b)},g.polygon=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polygon",b)},function(){function d(){return this.selectAll("stop")}function e(a,b){var d=k("stop"),e={offset:+b+"%"};return a=c.color(a),e["stop-color"]=a.hex,a.opacity<1&&(e["stop-opacity"]=a.opacity),k(d,e),this.node.appendChild(d),this}function f(){if("linearGradient"==this.type){var a=k(this.node,"x1")||0,b=k(this.node,"x2")||1,d=k(this.node,"y1")||0,e=k(this.node,"y2")||0;return c._.box(a,d,math.abs(b-a),math.abs(e-d))}var f=this.node.cx||.5,g=this.node.cy||.5,h=this.node.r||0;return c._.box(f-h,g-h,2*h,2*h)}function h(a,c){function d(a,b){for(var c=(b-l)/(a-m),d=m;a>d;d++)g[d].offset=+(+l+c*(d-m)).toFixed(2);m=a,l=b}var e,f=b("snap.util.grad.parse",null,c).firstDefined();if(!f)return null;f.params.unshift(a),e="l"==f.type.toLowerCase()?i.apply(0,f.params):j.apply(0,f.params),f.type!=f.type.toLowerCase()&&k(e.node,{gradientUnits:"userSpaceOnUse"});var g=f.stops,h=g.length,l=0,m=0;h--;for(var n=0;h>n;n++)"offset"in g[n]&&d(n,g[n].offset);for(g[h].offset=g[h].offset||100,d(h,g[h].offset),n=0;h>=n;n++){var o=g[n];e.addStop(o.color,o.offset)}return e}function i(a,b,g,h,i){var j=c._.make("linearGradient",a);return j.stops=d,j.addStop=e,j.getBBox=f,null!=b&&k(j.node,{x1:b,y1:g,x2:h,y2:i}),j}function j(a,b,g,h,i,j){var l=c._.make("radialGradient",a);return l.stops=d,l.addStop=e,l.getBBox=f,null!=b&&k(l.node,{cx:b,cy:g,r:h}),null!=i&&null!=j&&k(l.node,{fx:i,fy:j}),l}var k=c._.$;g.gradient=function(a){return h(this.defs,a)},g.gradientLinear=function(a,b,c,d){return i(this.defs,a,b,c,d)},g.gradientRadial=function(a,b,c,d,e){return j(this.defs,a,b,c,d,e)},g.toString=function(){var a,b=this.node.ownerDocument,d=b.createDocumentFragment(),e=b.createElement("div"),f=this.node.cloneNode(!0);return d.appendChild(e),e.appendChild(f),c._.$(f,{xmlns:"http://www.w3.org/2000/svg"}),a=e.innerHTML,d.removeChild(d.firstChild),a},g.toDataURL=function(){return a&&a.btoa?"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(this))):void 0},g.clear=function(){for(var a,b=this.node.firstChild;b;)a=b.nextSibling,"defs"!=b.tagName?b.parentNode.removeChild(b):g.clear.call({node:b}),b=a}}()}),d.plugin(function(a,b){function c(a){var b=c.ps=c.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[K](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]}function d(a,b,c,d){return null==a&&(a=b=c=d=0),null==b&&(b=a.y,c=a.width,d=a.height,a=a.x),{x:a,y:b,width:c,w:c,height:d,h:d,x2:a+c,y2:b+d,cx:a+c/2,cy:b+d/2,r1:N.min(c,d)/2,r2:N.max(c,d)/2,r0:N.sqrt(c*c+d*d)/2,path:w(a,b,c,d),vb:[a,b,c,d].join(" ")}}function e(){return this.join(",").replace(L,"$1")}function f(a){var b=J(a);return b.toString=e,b}function g(a,b,c,d,e,f,g,h,j){return null==j?n(a,b,c,d,e,f,g,h):i(a,b,c,d,e,f,g,h,o(a,b,c,d,e,f,g,h,j))}function h(c,d){function e(a){return+(+a).toFixed(3)}return a._.cacher(function(a,f,h){a instanceof b&&(a=a.attr("d")),a=E(a);for(var j,k,l,m,n,o="",p={},q=0,r=0,s=a.length;s>r;r++){if(l=a[r],"M"==l[0])j=+l[1],k=+l[2];else{if(m=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6]),q+m>f){if(d&&!p.start){if(n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q),o+=["C"+e(n.start.x),e(n.start.y),e(n.m.x),e(n.m.y),e(n.x),e(n.y)],h)return o;p.start=o,o=["M"+e(n.x),e(n.y)+"C"+e(n.n.x),e(n.n.y),e(n.end.x),e(n.end.y),e(l[5]),e(l[6])].join(),q+=m,j=+l[5],k=+l[6];continue}if(!c&&!d)return n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q)}q+=m,j=+l[5],k=+l[6]}o+=l.shift()+l}return p.end=o,n=c?q:d?p:i(j,k,l[0],l[1],l[2],l[3],l[4],l[5],1)},null,a._.clone)}function i(a,b,c,d,e,f,g,h,i){var j=1-i,k=R(j,3),l=R(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*N.atan2(q-s,r-t)/O;return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}}function j(b,c,e,f,g,h,i,j){a.is(b,"array")||(b=[b,c,e,f,g,h,i,j]);var k=D.apply(null,b);return d(k.min.x,k.min.y,k.max.x-k.min.x,k.max.y-k.min.y)}function k(a,b,c){return b>=a.x&&b<=a.x+a.width&&c>=a.y&&c<=a.y+a.height}function l(a,b){return a=d(a),b=d(b),k(b,a.x,a.y)||k(b,a.x2,a.y)||k(b,a.x,a.y2)||k(b,a.x2,a.y2)||k(a,b.x,b.y)||k(a,b.x2,b.y)||k(a,b.x,b.y2)||k(a,b.x2,b.y2)||(a.x<b.x2&&a.x>b.x||b.x<a.x2&&b.x>a.x)&&(a.y<b.y2&&a.y>b.y||b.y<a.y2&&b.y>a.y)}function m(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function n(a,b,c,d,e,f,g,h,i){null==i&&(i=1),i=i>1?1:0>i?0:i;for(var j=i/2,k=12,l=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;k>p;p++){var q=j*l[p]+j,r=m(q,a,c,e,g),s=m(q,b,d,f,h),t=r*r+s*s;o+=n[p]*N.sqrt(t)}return j*o}function o(a,b,c,d,e,f,g,h,i){if(!(0>i||n(a,b,c,d,e,f,g,h)<i)){var j,k=1,l=k/2,m=k-l,o=.01;for(j=n(a,b,c,d,e,f,g,h,m);S(j-i)>o;)l/=2,m+=(i>j?1:-1)*l,j=n(a,b,c,d,e,f,g,h,m);return m}}function p(a,b,c,d,e,f,g,h){if(!(Q(a,c)<P(e,g)||P(a,c)>Q(e,g)||Q(b,d)<P(f,h)||P(b,d)>Q(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+Q(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+Q(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+Q(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+Q(f,h).toFixed(2)))return{x:l,y:m}}}}function q(a,b,c){var d=j(a),e=j(b);if(!l(d,e))return c?0:[];for(var f=n.apply(0,a),g=n.apply(0,b),h=~~(f/8),k=~~(g/8),m=[],o=[],q={},r=c?0:[],s=0;h+1>s;s++){var t=i.apply(0,a.concat(s/h));m.push({x:t.x,y:t.y,t:s/h})}for(s=0;k+1>s;s++)t=i.apply(0,b.concat(s/k)),o.push({x:t.x,y:t.y,t:s/k});for(s=0;h>s;s++)for(var u=0;k>u;u++){var v=m[s],w=m[s+1],x=o[u],y=o[u+1],z=S(w.x-v.x)<.001?"y":"x",A=S(y.x-x.x)<.001?"y":"x",B=p(v.x,v.y,w.x,w.y,x.x,x.y,y.x,y.y);if(B){if(q[B.x.toFixed(4)]==B.y.toFixed(4))continue;q[B.x.toFixed(4)]=B.y.toFixed(4);var C=v.t+S((B[z]-v[z])/(w[z]-v[z]))*(w.t-v.t),D=x.t+S((B[A]-x[A])/(y[A]-x[A]))*(y.t-x.t);C>=0&&1>=C&&D>=0&&1>=D&&(c?r++:r.push({x:B.x,y:B.y,t1:C,t2:D}))}}return r}function r(a,b){return t(a,b)}function s(a,b){return t(a,b,1)}function t(a,b,c){a=E(a),b=E(b);for(var d,e,f,g,h,i,j,k,l,m,n=c?0:[],o=0,p=a.length;p>o;o++){var r=a[o];if("M"==r[0])d=h=r[1],e=i=r[2];else{"C"==r[0]?(l=[d,e].concat(r.slice(1)),d=l[6],e=l[7]):(l=[d,e,d,e,h,i,h,i],d=h,e=i);for(var s=0,t=b.length;t>s;s++){var u=b[s];if("M"==u[0])f=j=u[1],g=k=u[2];else{"C"==u[0]?(m=[f,g].concat(u.slice(1)),f=m[6],g=m[7]):(m=[f,g,f,g,j,k,j,k],f=j,g=k);var v=q(l,m,c);if(c)n+=v;else{for(var w=0,x=v.length;x>w;w++)v[w].segment1=o,v[w].segment2=s,v[w].bez1=l,v[w].bez2=m;n=n.concat(v)}}}}}return n}function u(a,b,c){var d=v(a);return k(d,b,c)&&t(a,[["M",b,c],["H",d.x2+10]],1)%2==1}function v(a){var b=c(a);if(b.bbox)return J(b.bbox);if(!a)return d();a=E(a);for(var e,f=0,g=0,h=[],i=[],j=0,k=a.length;k>j;j++)if(e=a[j],"M"==e[0])f=e[1],g=e[2],h.push(f),i.push(g);else{var l=D(f,g,e[1],e[2],e[3],e[4],e[5],e[6]);h=h.concat(l.min.x,l.max.x),i=i.concat(l.min.y,l.max.y),f=e[5],g=e[6]}var m=P.apply(0,h),n=P.apply(0,i),o=Q.apply(0,h),p=Q.apply(0,i),q=d(m,n,o-m,p-n);return b.bbox=J(q),q}function w(a,b,c,d,f){if(f)return[["M",+a+ +f,b],["l",c-2*f,0],["a",f,f,0,0,1,f,f],["l",0,d-2*f],["a",f,f,0,0,1,-f,f],["l",2*f-c,0],["a",f,f,0,0,1,-f,-f],["l",0,2*f-d],["a",f,f,0,0,1,f,-f],["z"]];var g=[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]];return g.toString=e,g}function x(a,b,c,d,f){if(null==f&&null==d&&(d=c),a=+a,b=+b,c=+c,d=+d,null!=f)var g=Math.PI/180,h=a+c*Math.cos(-d*g),i=a+c*Math.cos(-f*g),j=b+c*Math.sin(-d*g),k=b+c*Math.sin(-f*g),l=[["M",h,j],["A",c,c,0,+(f-d>180),0,i,k]];else l=[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]];return l.toString=e,l}function y(b){var d=c(b),g=String.prototype.toLowerCase;if(d.rel)return f(d.rel);a.is(b,"array")&&a.is(b&&b[0],"array")||(b=a.parsePathString(b));var h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=b[0][1],j=b[0][2],k=i,l=j,m++,h.push(["M",i,j]));for(var n=m,o=b.length;o>n;n++){var p=h[n]=[],q=b[n];if(q[0]!=g.call(q[0]))switch(p[0]=g.call(q[0]),p[0]){case"a":p[1]=q[1],p[2]=q[2],p[3]=q[3],p[4]=q[4],p[5]=q[5],p[6]=+(q[6]-i).toFixed(3),p[7]=+(q[7]-j).toFixed(3);break;case"v":p[1]=+(q[1]-j).toFixed(3);break;case"m":k=q[1],l=q[2];default:for(var r=1,s=q.length;s>r;r++)p[r]=+(q[r]-(r%2?i:j)).toFixed(3)}else{p=h[n]=[],"m"==q[0]&&(k=q[1]+i,l=q[2]+j);for(var t=0,u=q.length;u>t;t++)h[n][t]=q[t]}var v=h[n].length;switch(h[n][0]){case"z":i=k,j=l;break;case"h":i+=+h[n][v-1];break;case"v":j+=+h[n][v-1];break;default:i+=+h[n][v-2],j+=+h[n][v-1]}}return h.toString=e,d.rel=f(h),h}function z(b){var d=c(b);if(d.abs)return f(d.abs);if(I(b,"array")&&I(b&&b[0],"array")||(b=a.parsePathString(b)),!b||!b.length)return[["M",0,0]];var g,h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=+b[0][1],j=+b[0][2],k=i,l=j,m++,h[0]=["M",i,j]);for(var n,o,p=3==b.length&&"M"==b[0][0]&&"R"==b[1][0].toUpperCase()&&"Z"==b[2][0].toUpperCase(),q=m,r=b.length;r>q;q++){if(h.push(n=[]),o=b[q],g=o[0],g!=g.toUpperCase())switch(n[0]=g.toUpperCase(),n[0]){case"A":n[1]=o[1],n[2]=o[2],n[3]=o[3],n[4]=o[4],n[5]=o[5],n[6]=+o[6]+i,n[7]=+o[7]+j;break;case"V":n[1]=+o[1]+j;break;case"H":n[1]=+o[1]+i;break;case"R":for(var s=[i,j].concat(o.slice(1)),t=2,u=s.length;u>t;t++)s[t]=+s[t]+i,s[++t]=+s[t]+j;h.pop(),h=h.concat(G(s,p));break;case"O":h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);break;case"U":h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));break;case"M":k=+o[1]+i,l=+o[2]+j;default:for(t=1,u=o.length;u>t;t++)n[t]=+o[t]+(t%2?i:j)}else if("R"==g)s=[i,j].concat(o.slice(1)),h.pop(),h=h.concat(G(s,p)),n=["R"].concat(o.slice(-2));else if("O"==g)h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);else if("U"==g)h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));else for(var v=0,w=o.length;w>v;v++)n[v]=o[v];if(g=g.toUpperCase(),"O"!=g)switch(n[0]){case"Z":i=+k,j=+l;break;case"H":i=n[1];break;case"V":j=n[1];break;case"M":k=n[n.length-2],l=n[n.length-1];default:i=n[n.length-2],j=n[n.length-1]}}return h.toString=e,d.abs=f(h),h}function A(a,b,c,d){return[a,b,c,d,c,d]}function B(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]}function C(b,c,d,e,f,g,h,i,j,k){var l,m=120*O/180,n=O/180*(+f||0),o=[],p=a._.cacher(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(b,c,-n),b=l.x,c=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(O/180*f),N.sin(O/180*f),(b-i)/2),r=(c-j)/2,s=q*q/(d*d)+r*r/(e*e);s>1&&(s=N.sqrt(s),d=s*d,e=s*e);var t=d*d,u=e*e,v=(g==h?-1:1)*N.sqrt(S((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*d*r/e+(b+i)/2,x=v*-e*q/d+(c+j)/2,y=N.asin(((c-x)/e).toFixed(9)),z=N.asin(((j-x)/e).toFixed(9));y=w>b?O-y:y,z=w>i?O-z:z,0>y&&(y=2*O+y),0>z&&(z=2*O+z),h&&y>z&&(y-=2*O),!h&&z>y&&(z-=2*O)}var A=z-y;if(S(A)>m){var B=z,D=i,E=j;z=y+m*(h&&z>y?1:-1),i=w+d*N.cos(z),j=x+e*N.sin(z),o=C(i,j,d,e,f,0,h,D,E,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),J=N.tan(A/4),K=4/3*d*J,L=4/3*e*J,M=[b,c],P=[b+K*G,c-L*F],Q=[i+K*I,j-L*H],R=[i,j];if(P[0]=2*M[0]-P[0],P[1]=2*M[1]-P[1],k)return[P,Q,R].concat(o);o=[P,Q,R].concat(o).join().split(",");for(var T=[],U=0,V=o.length;V>U;U++)T[U]=U%2?p(o[U-1],o[U],n).y:p(o[U],o[U+1],n).x;return T}function D(a,b,c,d,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=[],r=[[],[]],s=0;2>s;++s)if(0==s?(j=6*a-12*c+6*e,i=-3*a+9*c-9*e+3*g,k=3*c-3*a):(j=6*b-12*d+6*f,i=-3*b+9*d-9*f+3*h,k=3*d-3*b),S(i)<1e-12){if(S(j)<1e-12)continue;l=-k/j,l>0&&1>l&&q.push(l)}else o=j*j-4*k*i,p=N.sqrt(o),0>o||(m=(-j+p)/(2*i),m>0&&1>m&&q.push(m),n=(-j-p)/(2*i),n>0&&1>n&&q.push(n));for(var t,u=q.length,v=u;u--;)l=q[u],t=1-l,r[0][u]=t*t*t*a+3*t*t*l*c+3*t*l*l*e+l*l*l*g,r[1][u]=t*t*t*b+3*t*t*l*d+3*t*l*l*f+l*l*l*h;return r[0][v]=a,r[1][v]=b,r[0][v+1]=g,r[1][v+1]=h,r[0].length=r[1].length=v+2,{min:{x:P.apply(0,r[0]),y:P.apply(0,r[1])},max:{x:Q.apply(0,r[0]),y:Q.apply(0,r[1])}}}function E(a,b){var d=!b&&c(a);if(!b&&d.curve)return f(d.curve);for(var e=z(a),g=b&&z(b),h={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},i={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},j=(function(a,b,c){var d,e;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"].concat(C.apply(0,[b.x,b.y].concat(a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e].concat(a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"].concat(B(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"].concat(B(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"].concat(A(b.x,b.y,a[1],a[2]));break;case"H":a=["C"].concat(A(b.x,b.y,a[1],b.y));break;case"V":a=["C"].concat(A(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"].concat(A(b.x,b.y,b.X,b.Y))}return a}),k=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)m[b]="A",g&&(n[b]="A"),a.splice(b++,0,["C"].concat(c.splice(0,6)));a.splice(b,1),r=Q(e.length,g&&g.length||0)}},l=function(a,b,c,d,f){a&&b&&"M"==a[f][0]&&"M"!=b[f][0]&&(b.splice(f,0,["M",d.x,d.y]),c.bx=0,c.by=0,c.x=a[f][1],c.y=a[f][2],r=Q(e.length,g&&g.length||0))},m=[],n=[],o="",p="",q=0,r=Q(e.length,g&&g.length||0);r>q;q++){e[q]&&(o=e[q][0]),"C"!=o&&(m[q]=o,q&&(p=m[q-1])),e[q]=j(e[q],h,p),"A"!=m[q]&&"C"==o&&(m[q]="C"),k(e,q),g&&(g[q]&&(o=g[q][0]),"C"!=o&&(n[q]=o,q&&(p=n[q-1])),g[q]=j(g[q],i,p),"A"!=n[q]&&"C"==o&&(n[q]="C"),k(g,q)),l(e,g,h,i,q),l(g,e,i,h,q);var s=e[q],t=g&&g[q],u=s.length,v=g&&t.length;h.x=s[u-2],h.y=s[u-1],h.bx=M(s[u-4])||h.x,h.by=M(s[u-3])||h.y,i.bx=g&&(M(t[v-4])||i.x),i.by=g&&(M(t[v-3])||i.y),i.x=g&&t[v-2],i.y=g&&t[v-1]}return g||(d.curve=f(e)),g?[e,g]:e}function F(a,b){if(!b)return a;var c,d,e,f,g,h,i;for(a=E(a),e=0,g=a.length;g>e;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a}function G(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}var H=b.prototype,I=a.is,J=a._.clone,K="hasOwnProperty",L=/,?([a-z]),?/gi,M=parseFloat,N=Math,O=N.PI,P=N.min,Q=N.max,R=N.pow,S=N.abs,T=h(1),U=h(),V=h(0,1),W=a._unit2px,X={path:function(a){return a.attr("path")},circle:function(a){var b=W(a);return x(b.cx,b.cy,b.r)},ellipse:function(a){var b=W(a);return x(b.cx||0,b.cy||0,b.rx,b.ry)},rect:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height,b.rx,b.ry)},image:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height)},line:function(a){return"M"+[a.attr("x1")||0,a.attr("y1")||0,a.attr("x2"),a.attr("y2")]},polyline:function(a){return"M"+a.attr("points")},polygon:function(a){return"M"+a.attr("points")+"z"},deflt:function(a){var b=a.node.getBBox();return w(b.x,b.y,b.width,b.height)}};a.path=c,a.path.getTotalLength=T,a.path.getPointAtLength=U,a.path.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return V(a,b).end;var d=V(a,c,1);return b?V(d,b).end:d},H.getTotalLength=function(){return this.node.getTotalLength?this.node.getTotalLength():void 0},H.getPointAtLength=function(a){return U(this.attr("d"),a)},H.getSubpath=function(b,c){return a.path.getSubpath(this.attr("d"),b,c)},a._.box=d,a.path.findDotsAtSegment=i,a.path.bezierBBox=j,a.path.isPointInsideBBox=k,a.closest=function(b,c,e,f){for(var g=100,h=d(b-g/2,c-g/2,g,g),i=[],j=e[0].hasOwnProperty("x")?function(a){return{x:e[a].x,y:e[a].y}}:function(a){return{x:e[a],y:f[a]}},l=0;1e6>=g&&!l;){for(var m=0,n=e.length;n>m;m++){var o=j(m);if(k(h,o.x,o.y)){l++,i.push(o);break}}l||(g*=2,h=d(b-g/2,c-g/2,g,g))}if(1e6!=g){var p,q=1/0;for(m=0,n=i.length;n>m;m++){var r=a.len(b,c,i[m].x,i[m].y);q>r&&(q=r,i[m].len=r,p=i[m])}return p}},a.path.isBBoxIntersect=l,a.path.intersection=r,a.path.intersectionNumber=s,a.path.isPointInside=u,a.path.getBBox=v,a.path.get=X,a.path.toRelative=y,a.path.toAbsolute=z,a.path.toCubic=E,a.path.map=F,a.path.toString=e,a.path.clone=f}),d.plugin(function(a){var d=Math.max,e=Math.min,f=function(a){if(this.items=[],this.bindings={},this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)a[b]&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},g=f.prototype;g.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],a&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},g.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},g.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this},g.animate=function(d,e,f,g){"function"!=typeof f||f.length||(g=f,f=c.linear),d instanceof a._.Animation&&(g=d.callback,f=d.easing,e=f.dur,d=d.attr);var h=arguments;if(a.is(d,"array")&&a.is(h[h.length-1],"array"))var i=!0;var j,k=function(){j?this.b=j:j=this.b},l=0,m=this,n=g&&function(){++l==m.length&&g.call(this) +};return this.forEach(function(a,c){b.once("snap.animcreated."+a.id,k),i?h[c]&&a.animate.apply(a,h[c]):a.animate(d,e,f,n)})},g.remove=function(){for(;this.length;)this.pop().remove();return this},g.bind=function(a,b,c){var d={};if("function"==typeof b)this.bindings[a]=b;else{var e=c||a;this.bindings[a]=function(a){d[e]=a,b.attr(d)}}return this},g.attr=function(a){var b={};for(var c in a)this.bindings[c]?this.bindings[c](a[c]):b[c]=a[c];for(var d=0,e=this.items.length;e>d;d++)this.items[d].attr(b);return this},g.clear=function(){for(;this.length;)this.pop()},g.splice=function(a,b){a=0>a?d(this.length+a,0):a,b=d(0,e(this.length-a,b));var c,g=[],h=[],i=[];for(c=2;c<arguments.length;c++)i.push(arguments[c]);for(c=0;b>c;c++)h.push(this[a+c]);for(;c<this.length-a;c++)g.push(this[a+c]);var j=i.length;for(c=0;c<j+g.length;c++)this.items[a+c]=this[a+c]=j>c?i[c]:g[c-j];for(c=this.items.length=this.length-=b-j;this[c];)delete this[c++];return new f(h)},g.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0;return!1},g.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},g.getBBox=function(){for(var a=[],b=[],c=[],f=[],g=this.items.length;g--;)if(!this.items[g].removed){var h=this.items[g].getBBox();a.push(h.x),b.push(h.y),c.push(h.x+h.width),f.push(h.y+h.height)}return a=e.apply(0,a),b=e.apply(0,b),c=d.apply(0,c),f=d.apply(0,f),{x:a,y:b,x2:c,y2:f,width:c-a,height:f-b,cx:a+(c-a)/2,cy:b+(f-b)/2}},g.clone=function(a){a=new f;for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},g.toString=function(){return"Snap‘s set"},g.type="set",a.Set=f,a.set=function(){var a=new f;return arguments.length&&a.push.apply(a,Array.prototype.slice.call(arguments,0)),a}}),d.plugin(function(a,c){function d(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}}function e(b,c,e){c=p(c).replace(/\.{3}|\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];for(var f,g,h,i,l=Math.max(b.length,c.length),m=[],n=[],o=0;l>o;o++){if(h=b[o]||d(c[o]),i=c[o]||d(h),h[0]!=i[0]||"r"==h[0].toLowerCase()&&(h[2]!=i[2]||h[3]!=i[3])||"s"==h[0].toLowerCase()&&(h[3]!=i[3]||h[4]!=i[4])){b=a._.transform2matrix(b,e()),c=a._.transform2matrix(c,e()),m=[["m",b.a,b.b,b.c,b.d,b.e,b.f]],n=[["m",c.a,c.b,c.c,c.d,c.e,c.f]];break}for(m[o]=[],n[o]=[],f=0,g=Math.max(h.length,i.length);g>f;f++)f in h&&(m[o][f]=h[f]),f in i&&(n[o][f]=i[f])}return{from:k(m),to:k(n),f:j(m)}}function f(a){return a}function g(a){return function(b){return+b.toFixed(3)+a}}function h(a){return a.join(" ")}function i(b){return a.rgb(b[0],b[1],b[2])}function j(a){var b,c,d,e,f,g,h=0,i=[];for(b=0,c=a.length;c>b;b++){for(f="[",g=['"'+a[b][0]+'"'],d=1,e=a[b].length;e>d;d++)g[d]="val["+h++ +"]";f+=g+"]",i[b]=f}return Function("val","return Snap.path.toString.call(["+i+"])")}function k(a){for(var b=[],c=0,d=a.length;d>c;c++)for(var e=1,f=a[c].length;f>e;e++)b.push(a[c][e]);return b}function l(a){return isFinite(parseFloat(a))}function m(b,c){return a.is(b,"array")&&a.is(c,"array")?b.toString()==c.toString():!1}var n={},o=/[a-z]+$/i,p=String;n.stroke=n.fill="colour",c.prototype.equal=function(a,c){return b("snap.util.equal",this,a,c).firstDefined()},b.on("snap.util.equal",function(b,c){var d,q,r=p(this.attr(b)||""),s=this;if(l(r)&&l(c))return{from:parseFloat(r),to:parseFloat(c),f:f};if("colour"==n[b])return d=a.color(r),q=a.color(c),{from:[d.r,d.g,d.b,d.opacity],to:[q.r,q.g,q.b,q.opacity],f:i};if("viewBox"==b)return d=this.attr(b).vb.split(" ").map(Number),q=c.split(" ").map(Number),{from:d,to:q,f:h};if("transform"==b||"gradientTransform"==b||"patternTransform"==b)return c instanceof a.Matrix&&(c=c.toTransformString()),a._.rgTransform.test(c)||(c=a._.svgTransform2string(c)),e(r,c,function(){return s.getBBox(1)});if("d"==b||"path"==b)return d=a.path.toCubic(r,c),{from:k(d[0]),to:k(d[1]),f:j(d[0])};if("points"==b)return d=p(r).split(a._.separator),q=p(c).split(a._.separator),{from:d,to:q,f:function(a){return a}};var t=r.match(o),u=p(c).match(o);return t&&m(t,u)?{from:parseFloat(r),to:parseFloat(c),f:g(t)}:{from:this.asPX(b),to:this.asPX(b,c),f:f}})}),d.plugin(function(a,c,d,e){for(var f=c.prototype,g="hasOwnProperty",h=("createTouch"in e.doc),i=["click","dblclick","mousedown","mousemove","mouseout","mouseover","mouseup","touchstart","touchmove","touchend","touchcancel"],j={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},k=(function(a,b){var c="y"==a?"scrollTop":"scrollLeft",d=b&&b.node?b.node.ownerDocument:e.doc;return d[c in d.documentElement?"documentElement":"body"][c]}),l=function(){return this.originalEvent.preventDefault()},m=function(){return this.originalEvent.stopPropagation()},n=function(a,b,c,d){var e=h&&j[b]?j[b]:b,f=function(e){var f=k("y",d),i=k("x",d);if(h&&j[g](b))for(var n=0,o=e.targetTouches&&e.targetTouches.length;o>n;n++)if(e.targetTouches[n].target==a||a.contains(e.targetTouches[n].target)){var p=e;e=e.targetTouches[n],e.originalEvent=p,e.preventDefault=l,e.stopPropagation=m;break}var q=e.clientX+i,r=e.clientY+f;return c.call(d,e,q,r)};return b!==e&&a.addEventListener(b,f,!1),a.addEventListener(e,f,!1),function(){return b!==e&&a.removeEventListener(b,f,!1),a.removeEventListener(e,f,!1),!0}},o=[],p=function(a){for(var c,d=a.clientX,e=a.clientY,f=k("y"),g=k("x"),i=o.length;i--;){if(c=o[i],h){for(var j,l=a.touches&&a.touches.length;l--;)if(j=a.touches[l],j.identifier==c.el._drag.id||c.el.node.contains(j.target)){d=j.clientX,e=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();{var m=c.el.node;m.nextSibling,m.parentNode,m.style.display}d+=g,e+=f,b("snap.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},q=function(c){a.unmousemove(p).unmouseup(q);for(var d,e=o.length;e--;)d=o[e],d.el._drag={},b("snap.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,c),b.off("snap.drag.*."+d.el.id);o=[]},r=i.length;r--;)!function(b){a[b]=f[b]=function(c,d){if(a.is(c,"function"))this.events=this.events||[],this.events.push({name:b,f:c,unbind:n(this.node||document,b,c,d||this)});else for(var e=0,f=this.events.length;f>e;e++)if(this.events[e].name==b)try{this.events[e].f.call(this)}catch(g){}return this},a["un"+b]=f["un"+b]=function(a){for(var c=this.events||[],d=c.length;d--;)if(c[d].name==b&&(c[d].f==a||!a))return c[d].unbind(),c.splice(d,1),!c.length&&delete this.events,this;return this}}(i[r]);f.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},f.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var s=[];f.drag=function(c,d,e,f,g,h){function i(i,j,l){(i.originalEvent||i).preventDefault(),k._drag.x=j,k._drag.y=l,k._drag.id=i.identifier,!o.length&&a.mousemove(p).mouseup(q),o.push({el:k,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("snap.drag.start."+k.id,d),c&&b.on("snap.drag.move."+k.id,c),e&&b.on("snap.drag.end."+k.id,e),b("snap.drag.start."+k.id,g||f||k,j,l,i)}function j(a,c,d){b("snap.draginit."+k.id,k,a,c,d)}var k=this;if(!arguments.length){var l;return k.drag(function(a,b){this.attr({transform:l+(l?"T":"t")+[a,b]})},function(){l=this.transform().local})}return b.on("snap.draginit."+k.id,i),k._drag={},s.push({el:k,start:i,init:j}),k.mousedown(j),k},f.undrag=function(){for(var c=s.length;c--;)s[c].el==this&&(this.unmousedown(s[c].init),s.splice(c,1),b.unbind("snap.drag.*."+this.id),b.unbind("snap.draginit."+this.id));return!s.length&&a.unmousemove(p).unmouseup(q),this}}),d.plugin(function(a,c,d){var e=(c.prototype,d.prototype),f=/^\s*url\((.+)\)/,g=String,h=a._.$;a.filter={},e.filter=function(b){var d=this;"svg"!=d.type&&(d=d.paper);var e=a.parse(g(b)),f=a._.id(),i=(d.node.offsetWidth,d.node.offsetHeight,h("filter"));return h(i,{id:f,filterUnits:"userSpaceOnUse"}),i.appendChild(e.node),d.defs.appendChild(i),new c(i)},b.on("snap.util.getattr.filter",function(){b.stop();var c=h(this.node,"filter");if(c){var d=g(c).match(f);return d&&a.select(d[1])}}),b.on("snap.util.attr.filter",function(d){if(d instanceof c&&"filter"==d.type){b.stop();var e=d.node.id;e||(h(d.node,{id:d.id}),e=d.id),h(this.node,{filter:a.url(e)})}d&&"none"!=d||(b.stop(),this.node.removeAttribute("filter"))}),a.filter.blur=function(b,c){null==b&&(b=2);var d=null==c?b:[b,c];return a.format('<feGaussianBlur stdDeviation="{def}"/>',{def:d})},a.filter.blur.toString=function(){return this()},a.filter.shadow=function(b,c,d,e,f){return"string"==typeof d&&(e=d,f=e,d=4),"string"!=typeof e&&(f=e,e="#000"),e=e||"#000",null==d&&(d=4),null==f&&(f=1),null==b&&(b=0,c=2),null==c&&(c=b),e=a.color(e),a.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>',{color:e,dx:b,dy:c,blur:d,opacity:f})},a.filter.shadow.toString=function(){return this()},a.filter.grayscale=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>',{a:.2126+.7874*(1-b),b:.7152-.7152*(1-b),c:.0722-.0722*(1-b),d:.2126-.2126*(1-b),e:.7152+.2848*(1-b),f:.0722-.0722*(1-b),g:.2126-.2126*(1-b),h:.0722+.9278*(1-b)})},a.filter.grayscale.toString=function(){return this()},a.filter.sepia=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>',{a:.393+.607*(1-b),b:.769-.769*(1-b),c:.189-.189*(1-b),d:.349-.349*(1-b),e:.686+.314*(1-b),f:.168-.168*(1-b),g:.272-.272*(1-b),h:.534-.534*(1-b),i:.131+.869*(1-b)})},a.filter.sepia.toString=function(){return this()},a.filter.saturate=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="saturate" values="{amount}"/>',{amount:1-b})},a.filter.saturate.toString=function(){return this()},a.filter.hueRotate=function(b){return b=b||0,a.format('<feColorMatrix type="hueRotate" values="{angle}"/>',{angle:b})},a.filter.hueRotate.toString=function(){return this()},a.filter.invert=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>',{amount:b,amount2:1-b})},a.filter.invert.toString=function(){return this()},a.filter.brightness=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>',{amount:b})},a.filter.brightness.toString=function(){return this()},a.filter.contrast=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>',{amount:b,amount2:.5-b/2})},a.filter.contrast.toString=function(){return this()}}),d.plugin(function(a,b){var c=a._.box,d=a.is,e=/^[^a-z]*([tbmlrc])/i,f=function(){return"T"+this.dx+","+this.dy};b.prototype.getAlign=function(a,b){null==b&&d(a,"string")&&(b=a,a=null),a=a||this.paper;var g=a.getBBox?a.getBBox():c(a),h=this.getBBox(),i={};switch(b=b&&b.match(e),b=b?b[1].toLowerCase():"c"){case"t":i.dx=0,i.dy=g.y-h.y;break;case"b":i.dx=0,i.dy=g.y2-h.y2;break;case"m":i.dx=0,i.dy=g.cy-h.cy;break;case"l":i.dx=g.x-h.x,i.dy=0;break;case"r":i.dx=g.x2-h.x2,i.dy=0;break;default:i.dx=g.cx-h.cx,i.dy=0}return i.toString=f,i},b.prototype.align=function(a,b){return this.transform("..."+this.getAlign(a,b))}}),d}); diff --git a/web/pgadmin/misc/static/explain/js/snap.svg.js b/web/pgadmin/misc/static/explain/js/snap.svg.js new file mode 100644 index 0000000..ef0fb6d --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg.js @@ -0,0 +1,8149 @@ +// Snap.svg 0.4.1 +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// build: 2015-04-13 +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ┌────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.4.2 - JavaScript Events Library │ \\ +// ├────────────────────────────────────────────────────────────┤ \\ +// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// └────────────────────────────────────────────────────────────┘ \\ +(function (glob) { + var version = "0.4.2", + has = "hasOwnProperty", + separator = /[\.\/]/, + comaseparator = /\s*,\s*/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + firstDefined = function () { + for (var i = 0, ii = this.length; i < ii; i++) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + lastDefined = function () { + var i = this.length; + while (--i) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + /*\ + * eve + [ method ] + * Fires event with given `name`, given scope and other parameters. + > Arguments + - name (string) name of the *event*, dot (`.`) or slash (`/`) separated + - scope (object) context for the event handlers + - varargs (...) the rest of arguments will be sent to event handlers + = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value. + \*/ + eve = function (name, scope) { + name = String(name); + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + ce = current_event, + errors = []; + out.firstDefined = firstDefined; + out.lastDefined = lastDefined; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + break; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + } + } + stop = oldstop; + current_event = ce; + return out; + }; + // Undocumented. Debug only. + eve._events = events; + /*\ + * eve.listeners + [ method ] + * Internal method which gives you array of all event handlers that will be triggered by the given `name`. + > Arguments + - name (string) name of the event, dot (`.`) or slash (`/`) separated + = (array) array of event handlers + \*/ + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + /*\ + * eve.on + [ method ] + ** + * Binds given event handler with a given name. You can use wildcards “`*`” for the names: + | eve.on("*.under.*", f); + | eve("mouse.under.floor"); // triggers f + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. + > Example: + | eve.on("mouse", eatIt)(2); + | eve.on("mouse", scream); + | eve.on("mouse", catchIt)(1); + * This will ensure that `catchIt` function will be called before `eatIt`. + * + * If you want to put your handler before non-indexed handlers, specify a negative value. + * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. + \*/ + eve.on = function (name, f) { + name = String(name); + if (typeof f != "function") { + return function () {}; + } + var names = name.split(comaseparator); + for (var i = 0, ii = names.length; i < ii; i++) { + (function (name) { + var names = name.split(separator), + e = events, + exist; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + exist = true; + break; + } + !exist && e.f.push(f); + }(names[i])); + } + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + /*\ + * eve.f + [ method ] + ** + * Returns function that will fire given event with optional arguments. + * Arguments that will be passed to the result function will be also + * concated to the list of final arguments. + | el.onclick = eve.f("click", 1, 2); + | eve.on("click", function (a, b, c) { + | console.log(a, b, c); // 1, 2, [event object] + | }); + > Arguments + - event (string) event name + - varargs (…) and any other arguments + = (function) possible event handler function + \*/ + eve.f = function (event) { + var attrs = [].slice.call(arguments, 1); + return function () { + eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); + }; + }; + /*\ + * eve.stop + [ method ] + ** + * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. + \*/ + eve.stop = function () { + stop = 1; + }; + /*\ + * eve.nt + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + > Arguments + ** + - subname (string) #optional subname of the event + ** + = (string) name of the event, if `subname` is not specified + * or + = (boolean) `true`, if current event’s name contains `subname` + \*/ + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + /*\ + * eve.nts + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + ** + = (array) names of the event + \*/ + eve.nts = function () { + return current_event.split(separator); + }; + /*\ + * eve.off + [ method ] + ** + * Removes given function from the list of event listeners assigned to given name. + * If no arguments specified all the events will be cleared. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + \*/ + /*\ + * eve.unbind + [ method ] + ** + * See @eve.off + \*/ + eve.off = eve.unbind = function (name, f) { + if (!name) { + eve._events = events = {n: {}}; + return; + } + var names = name.split(comaseparator); + if (names.length > 1) { + for (var i = 0, ii = names.length; i < ii; i++) { + eve.off(names[i], f); + } + return; + } + names = name.split(separator); + var e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + /*\ + * eve.once + [ method ] + ** + * Binds given event handler with a given name to only run once then unbind itself. + | eve.once("login", f); + | eve("login"); // triggers f + | eve("login"); // no listeners + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) same return function as @eve.on + \*/ + eve.once = function (name, f) { + var f2 = function () { + eve.unbind(name, f2); + return f.apply(this, arguments); + }; + return eve.on(name, f2); + }; + /*\ + * eve.version + [ property (string) ] + ** + * Current version of the library. + \*/ + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define === "function" && define.amd ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); +})(this); + +(function (glob, factory) { + // AMD support + if (typeof define == "function" && define.amd) { + // Define as an anonymous module + define(["eve"], function (eve) { + return factory(glob, eve); + }); + } else if (typeof exports != 'undefined') { + // Next for Node.js or CommonJS + var eve = require('eve'); + module.exports = factory(glob, eve); + } else { + // Browser globals (glob is window) + // Snap adds itself to window + factory(glob, glob.eve); + } +}(window || this, function (window, eve) { +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +var mina = (function (eve) { + var animations = {}, + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + isArray = Array.isArray || function (a) { + return a instanceof Array || + Object.prototype.toString.call(a) == "[object Array]"; + }, + idgen = 0, + idprefix = "M" + (+new Date).toString(36), + ID = function () { + return idprefix + (idgen++).toString(36); + }, + diff = function (a, b, A, B) { + if (isArray(a)) { + res = []; + for (var i = 0, ii = a.length; i < ii; i++) { + res[i] = diff(a[i], b, A[i], B); + } + return res; + } + var dif = (A - a) / (B - b); + return function (bb) { + return a + dif * (bb - b); + }; + }, + timer = Date.now || function () { + return +new Date; + }, + sta = function (val) { + var a = this; + if (val == null) { + return a.s; + } + var ds = a.s - val; + a.b += a.dur * ds; + a.B += a.dur * ds; + a.s = val; + }, + speed = function (val) { + var a = this; + if (val == null) { + return a.spd; + } + a.spd = val; + }, + duration = function (val) { + var a = this; + if (val == null) { + return a.dur; + } + a.s = a.s * val / a.dur; + a.dur = val; + }, + stopit = function () { + var a = this; + delete animations[a.id]; + a.update(); + eve("mina.stop." + a.id, a); + }, + pause = function () { + var a = this; + if (a.pdif) { + return; + } + delete animations[a.id]; + a.update(); + a.pdif = a.get() - a.b; + }, + resume = function () { + var a = this; + if (!a.pdif) { + return; + } + a.b = a.get() - a.pdif; + delete a.pdif; + animations[a.id] = a; + }, + update = function () { + var a = this, + res; + if (isArray(a.start)) { + res = []; + for (var j = 0, jj = a.start.length; j < jj; j++) { + res[j] = +a.start[j] + + (a.end[j] - a.start[j]) * a.easing(a.s); + } + } else { + res = +a.start + (a.end - a.start) * a.easing(a.s); + } + a.set(res); + }, + frame = function () { + var len = 0; + for (var i in animations) if (animations.hasOwnProperty(i)) { + var a = animations[i], + b = a.get(), + res; + len++; + a.s = (b - a.b) / (a.dur / a.spd); + if (a.s >= 1) { + delete animations[i]; + a.s = 1; + len--; + (function (a) { + setTimeout(function () { + eve("mina.finish." + a.id, a); + }); + }(a)); + } + a.update(); + } + len && requestAnimFrame(frame); + }, + /*\ + * mina + [ method ] + ** + * Generic animation of numbers + ** + - a (number) start _slave_ number + - A (number) end _slave_ number + - b (number) start _master_ number (start time in general case) + - B (number) end _master_ number (end time in gereal case) + - get (function) getter of _master_ number (see @mina.time) + - set (function) setter of _slave_ number + - easing (function) #optional easing function, default is @mina.linear + = (object) animation descriptor + o { + o id (string) animation id, + o start (number) start _slave_ number, + o end (number) end _slave_ number, + o b (number) start _master_ number, + o s (number) animation status (0..1), + o dur (number) animation duration, + o spd (number) animation speed, + o get (function) getter of _master_ number (see @mina.time), + o set (function) setter of _slave_ number, + o easing (function) easing function, default is @mina.linear, + o status (function) status getter/setter, + o speed (function) speed getter/setter, + o duration (function) duration getter/setter, + o stop (function) animation stopper + o pause (function) pauses the animation + o resume (function) resumes the animation + o update (function) calles setter with the right value of the animation + o } + \*/ + mina = function (a, A, b, B, get, set, easing) { + var anim = { + id: ID(), + start: a, + end: A, + b: b, + s: 0, + dur: B - b, + spd: 1, + get: get, + set: set, + easing: easing || mina.linear, + status: sta, + speed: speed, + duration: duration, + stop: stopit, + pause: pause, + resume: resume, + update: update + }; + animations[anim.id] = anim; + var len = 0, i; + for (i in animations) if (animations.hasOwnProperty(i)) { + len++; + if (len == 2) { + break; + } + } + len == 1 && requestAnimFrame(frame); + return anim; + }; + /*\ + * mina.time + [ method ] + ** + * Returns the current time. Equivalent to: + | function () { + | return (new Date).getTime(); + | } + \*/ + mina.time = timer; + /*\ + * mina.getById + [ method ] + ** + * Returns an animation by its id + - id (string) animation's id + = (object) See @mina + \*/ + mina.getById = function (id) { + return animations[id] || null; + }; + + /*\ + * mina.linear + [ method ] + ** + * Default linear easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.linear = function (n) { + return n; + }; + /*\ + * mina.easeout + [ method ] + ** + * Easeout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeout = function (n) { + return Math.pow(n, 1.7); + }; + /*\ + * mina.easein + [ method ] + ** + * Easein easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easein = function (n) { + return Math.pow(n, .48); + }; + /*\ + * mina.easeinout + [ method ] + ** + * Easeinout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeinout = function (n) { + if (n == 1) { + return 1; + } + if (n == 0) { + return 0; + } + var q = .48 - n / 1.04, + Q = Math.sqrt(.1734 + q * q), + x = Q - q, + X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }; + /*\ + * mina.backin + [ method ] + ** + * Backin easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backin = function (n) { + if (n == 1) { + return 1; + } + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }; + /*\ + * mina.backout + [ method ] + ** + * Backout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backout = function (n) { + if (n == 0) { + return 0; + } + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }; + /*\ + * mina.elastic + [ method ] + ** + * Elastic easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.elastic = function (n) { + if (n == !!n) { + return n; + } + return Math.pow(2, -10 * n) * Math.sin((n - .075) * + (2 * Math.PI) / .3) + 1; + }; + /*\ + * mina.bounce + [ method ] + ** + * Bounce easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.bounce = function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + }; + window.mina = mina; + return mina; +})(typeof eve == "undefined" ? function () {} : eve); +// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var Snap = (function(root) { +Snap.version = "0.4.0"; +/*\ + * Snap + [ method ] + ** + * Creates a drawing surface or wraps existing SVG element. + ** + - width (number|string) width of surface + - height (number|string) height of surface + * or + - DOM (SVGElement) element to be wrapped into Snap structure + * or + - array (array) array of elements (will return set of elements) + * or + - query (string) CSS query selector + = (object) @Element +\*/ +function Snap(w, h) { + if (w) { + if (w.nodeType) { + return wrap(w); + } + if (is(w, "array") && Snap.set) { + return Snap.set.apply(Snap, w); + } + if (w instanceof Element) { + return w; + } + if (h == null) { + w = glob.doc.querySelector(String(w)); + return wrap(w); + } + } + w = w == null ? "100%" : w; + h = h == null ? "100%" : h; + return new Paper(w, h); +} +Snap.toString = function () { + return "Snap v" + this.version; +}; +Snap._ = {}; +var glob = { + win: root.window, + doc: root.window.document +}; +Snap._.glob = glob; +var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + round = math.round, + E = "", + S = " ", + objectToString = Object.prototype.toString, + ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + reURLValue = /^url\(#?([^)]+)\)$/, + separator = Snap._.separator = /[,\s]+/, + whitespace = /[\s]/g, + commaSpaces = /[\s]*,[\s]*/, + hsrg = {hs: 1, rg: 1}, + pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig, + idgen = 0, + idprefix = "S" + (+new Date).toString(36), + ID = function (el) { + return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36); + }, + xlink = "http://www.w3.org/1999/xlink", + xmlns = "http://www.w3.org/2000/svg", + hub = {}, + URL = Snap.url = function (url) { + return "url('#" + url + "')"; + }; + +function $(el, attr) { + if (attr) { + if (el == "#text") { + el = glob.doc.createTextNode(attr.text || attr["#text"] || ""); + } + if (el == "#comment") { + el = glob.doc.createComment(attr.text || attr["#text"] || ""); + } + if (typeof el == "string") { + el = $(el); + } + if (typeof attr == "string") { + if (el.nodeType == 1) { + if (attr.substring(0, 6) == "xlink:") { + return el.getAttributeNS(xlink, attr.substring(6)); + } + if (attr.substring(0, 4) == "xml:") { + return el.getAttributeNS(xmlns, attr.substring(4)); + } + return el.getAttribute(attr); + } else if (attr == "text") { + return el.nodeValue; + } else { + return null; + } + } + if (el.nodeType == 1) { + for (var key in attr) if (attr[has](key)) { + var val = Str(attr[key]); + if (val) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), val); + } else if (key.substring(0, 4) == "xml:") { + el.setAttributeNS(xmlns, key.substring(4), val); + } else { + el.setAttribute(key, val); + } + } else { + el.removeAttribute(key); + } + } + } else if ("text" in attr) { + el.nodeValue = attr.text; + } + } else { + el = glob.doc.createElementNS(xmlns, el); + } + return el; +} +Snap._.$ = $; +Snap._.id = ID; +function getAttrs(el) { + var attrs = el.attributes, + name, + out = {}; + for (var i = 0; i < attrs.length; i++) { + if (attrs[i].namespaceURI == xlink) { + name = "xlink:"; + } else { + name = ""; + } + name += attrs[i].name; + out[name] = attrs[i].textContent; + } + return out; +} +function is(o, type) { + type = Str.prototype.toLowerCase.call(type); + if (type == "finite") { + return isFinite(o); + } + if (type == "array" && + (o instanceof Array || Array.isArray && Array.isArray(o))) { + return true; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; +} +/*\ + * Snap.format + [ method ] + ** + * Replaces construction of type `{<name>}` to the corresponding argument + ** + - token (string) string to format + - json (object) object which properties are used as a replacement + = (string) formatted string + > Usage + | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z" + | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { + | x: 10, + | y: 20, + | dim: { + | width: 40, + | height: 50, + | "negative width": -40 + | } + | })); +\*/ +Snap.format = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return Str(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; +})(); +function clone(obj) { + if (typeof obj == "function" || Object(obj) !== obj) { + return obj; + } + var res = new obj.constructor; + for (var key in obj) if (obj[has](key)) { + res[key] = clone(obj[key]); + } + return res; +} +Snap._.clone = clone; +function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } +} +function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f.apply(scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; +} +Snap._.cacher = cacher; +function angle(x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3); + } +} +function rad(deg) { + return deg % 360 * PI / 180; +} +function deg(rad) { + return rad * 180 / PI % 360; +} +function x_y() { + return this.x + S + this.y; +} +function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; +} + +/*\ + * Snap.rad + [ method ] + ** + * Transform angle to radians + - deg (number) angle in degrees + = (number) angle in radians +\*/ +Snap.rad = rad; +/*\ + * Snap.deg + [ method ] + ** + * Transform angle to degrees + - rad (number) angle in radians + = (number) angle in degrees +\*/ +Snap.deg = deg; +/*\ + * Snap.sin + [ method ] + ** + * Equivalent to `Math.sin()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) sin +\*/ +Snap.sin = function (angle) { + return math.sin(Snap.rad(angle)); +}; +/*\ + * Snap.tan + [ method ] + ** + * Equivalent to `Math.tan()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) tan +\*/ +Snap.tan = function (angle) { + return math.tan(Snap.rad(angle)); +}; +/*\ + * Snap.cos + [ method ] + ** + * Equivalent to `Math.cos()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) cos +\*/ +Snap.cos = function (angle) { + return math.cos(Snap.rad(angle)); +}; +/*\ + * Snap.asin + [ method ] + ** + * Equivalent to `Math.asin()` only works with degrees, not radians. + - num (number) value + = (number) asin in degrees +\*/ +Snap.asin = function (num) { + return Snap.deg(math.asin(num)); +}; +/*\ + * Snap.acos + [ method ] + ** + * Equivalent to `Math.acos()` only works with degrees, not radians. + - num (number) value + = (number) acos in degrees +\*/ +Snap.acos = function (num) { + return Snap.deg(math.acos(num)); +}; +/*\ + * Snap.atan + [ method ] + ** + * Equivalent to `Math.atan()` only works with degrees, not radians. + - num (number) value + = (number) atan in degrees +\*/ +Snap.atan = function (num) { + return Snap.deg(math.atan(num)); +}; +/*\ + * Snap.atan2 + [ method ] + ** + * Equivalent to `Math.atan2()` only works with degrees, not radians. + - num (number) value + = (number) atan2 in degrees +\*/ +Snap.atan2 = function (num) { + return Snap.deg(math.atan2(num)); +}; +/*\ + * Snap.angle + [ method ] + ** + * Returns an angle between two or three points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + - x3 (number) #optional x coord of third point + - y3 (number) #optional y coord of third point + = (number) angle in degrees +\*/ +Snap.angle = angle; +/*\ + * Snap.len + [ method ] + ** + * Returns distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len = function (x1, y1, x2, y2) { + return Math.sqrt(Snap.len2(x1, y1, x2, y2)); +}; +/*\ + * Snap.len2 + [ method ] + ** + * Returns squared distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len2 = function (x1, y1, x2, y2) { + return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); +}; +/*\ + * Snap.closestPoint + [ method ] + ** + * Returns closest point to a given one on a given path. + > Parameters + - path (Element) path element + - x (number) x coord of a point + - y (number) y coord of a point + = (object) in format + { + x (number) x coord of the point on the path + y (number) y coord of the point on the path + length (number) length of the path to the point + distance (number) distance from the given point to the path + } +\*/ +// Copied from http://bl.ocks.org/mbostock/8027637 +Snap.closestPoint = function (path, x, y) { + function distance2(p) { + var dx = p.x - x, + dy = p.y - y; + return dx * dx + dy * dy; + } + var pathNode = path.node, + pathLength = pathNode.getTotalLength(), + precision = pathLength / pathNode.pathSegList.numberOfItems * .125, + best, + bestLength, + bestDistance = Infinity; + + // linear scan for coarse approximation + for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { + if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) { + best = scan, bestLength = scanLength, bestDistance = scanDistance; + } + } + + // binary search for precise estimate + precision *= .5; + while (precision > .5) { + var before, + after, + beforeLength, + afterLength, + beforeDistance, + afterDistance; + if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) { + best = before, bestLength = beforeLength, bestDistance = beforeDistance; + } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) { + best = after, bestLength = afterLength, bestDistance = afterDistance; + } else { + precision *= .5; + } + } + + best = { + x: best.x, + y: best.y, + length: bestLength, + distance: Math.sqrt(bestDistance) + }; + return best; +} +/*\ + * Snap.is + [ method ] + ** + * Handy replacement for the `typeof` operator + - o (…) any object or primitive + - type (string) name of the type, e.g., `string`, `function`, `number`, etc. + = (boolean) `true` if given value is of given type +\*/ +Snap.is = is; +/*\ + * Snap.snapTo + [ method ] + ** + * Snaps given value to given grid + - values (array|number) given array of values or step of the grid + - value (number) value to adjust + - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`. + = (number) adjusted value +\*/ +Snap.snapTo = function (values, value, tolerance) { + tolerance = is(tolerance, "finite") ? tolerance : 10; + if (is(values, "array")) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; +}; +// Colour +/*\ + * Snap.getRGB + [ method ] + ** + * Parses color string as RGB object + - color (string) color string in one of the following formats: + # <ul> + # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li> + # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li> + # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li> + # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li> + # <li>rgba(•••, •••, •••, •••) — also with opacity</li> + # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li> + # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li> + # <li>hsba(•••, •••, •••, •••) — also with opacity</li> + # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li> + # <li>hsla(•••, •••, •••, •••) — also with opacity</li> + # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li> + # </ul> + * Note that `%` can be used any time: `rgb(20%, 255, 50%)`. + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) true if string can't be parsed + o } +\*/ +Snap.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + if (!colour) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsl2rgb(red, green, blue, opacity); + } + red = mmin(math.round(red), 255); + green = mmin(math.round(green), 255); + blue = mmin(math.round(blue), 255); + opacity = mmin(mmax(opacity, 0), 1); + rgb = {r: red, g: green, b: blue, toString: rgbtoString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + rgb.opacity = is(opacity, "finite") ? opacity : 1; + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; +}, Snap); +/*\ + * Snap.hsb + [ method ] + ** + * Converts HSB values to a hex representation of the color + - h (number) hue + - s (number) saturation + - b (number) value or brightness + = (string) hex representation of the color +\*/ +Snap.hsb = cacher(function (h, s, b) { + return Snap.hsb2rgb(h, s, b).hex; +}); +/*\ + * Snap.hsl + [ method ] + ** + * Converts HSL values to a hex representation of the color + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (string) hex representation of the color +\*/ +Snap.hsl = cacher(function (h, s, l) { + return Snap.hsl2rgb(h, s, l).hex; +}); +/*\ + * Snap.rgb + [ method ] + ** + * Converts RGB values to a hex representation of the color + - r (number) red + - g (number) green + - b (number) blue + = (string) hex representation of the color +\*/ +Snap.rgb = cacher(function (r, g, b, o) { + if (is(o, "finite")) { + var round = math.round; + return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")"; + } + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); +}); +var toHex = function (color) { + var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0], + red = "rgb(255, 0, 0)"; + toHex = cacher(function (color) { + if (color.toLowerCase() == "red") { + return red; + } + i.style.color = red; + i.style.color = color; + var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + return out == red ? null : out; + }); + return toHex(color); +}, +hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; +}, +hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; +}, +rgbtoString = function () { + return this.opacity == 1 || this.opacity == null ? + this.hex : + "rgba(" + [this.r, this.g, this.b, this.opacity] + ")"; +}, +prepareRGB = function (r, g, b) { + if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && is(r, string)) { + var clr = Snap.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; +}, +packageRGB = function (r, g, b, o) { + r = math.round(r * 255); + g = math.round(g * 255); + b = math.round(b * 255); + var rgb = { + r: r, + g: g, + b: b, + opacity: is(o, "finite") ? o : 1, + hex: Snap.rgb(r, g, b), + toString: rgbtoString + }; + is(o, "finite") && (rgb.opacity = o); + return rgb; +}; +/*\ + * Snap.color + [ method ] + ** + * Parses the color string and returns an object featuring the color's component values + - clr (string) color string in one of the supported formats (see @Snap.getRGB) + = (object) Combined RGB/HSB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) `true` if string can't be parsed, + o h (number) hue, + o s (number) saturation, + o v (number) value (brightness), + o l (number) lightness + o } +\*/ +Snap.color = function (clr) { + var rgb; + if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = Snap.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = Snap.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else { + if (is(clr, "string")) { + clr = Snap.getRGB(clr); + } + if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) { + rgb = Snap.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = Snap.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + clr.error = 1; + } + } + clr.toString = rgbtoString; + return clr; +}; +/*\ + * Snap.hsb2rgb + [ method ] + ** + * Converts HSB values to an RGB object + - h (number) hue + - s (number) saturation + - v (number) value or brightness + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsb2rgb = function (h, s, v, o) { + if (is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + o = h.o; + h = h.h; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.hsl2rgb + [ method ] + ** + * Converts HSL values to an RGB object + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsl2rgb = function (h, s, l, o) { + if (is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.rgb2hsb + [ method ] + ** + * Converts RGB values to an HSB object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSB object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o b (number) brightness + o } +\*/ +Snap.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; +}; +/*\ + * Snap.rgb2hsl + [ method ] + ** + * Converts RGB values to an HSL object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSL object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o l (number) luminosity + o } +\*/ +Snap.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; +}; + +// Transformations +/*\ + * Snap.parsePathString + [ method ] + ** + * Utility method + ** + * Parses given path string into an array of arrays of path segments + - pathString (string|array) path string or array of segments (in the last case it is returned straight away) + = (array) array of segments +\*/ +Snap.parsePathString = function (pathString) { + if (!pathString) { + return null; + } + var pth = Snap.path(pathString); + if (pth.arr) { + return Snap.path.clone(pth.arr); + } + + var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0}, + data = []; + if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption + data = Snap.path.clone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b].concat(params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "o" && params.length == 1) { + data.push([b, params[0]]); + } + if (name == "r") { + data.push([b].concat(params)); + } else while (params.length >= paramCounts[name]) { + data.push([b].concat(params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = Snap.path.toString; + pth.arr = Snap.path.clone(data); + return data; +}; +/*\ + * Snap.parseTransformString + [ method ] + ** + * Utility method + ** + * Parses given transform string into an array of transformations + - TString (string|array) transform string or array of transformations (in the last case it is returned straight away) + = (array) array of transformations +\*/ +var parseTransformString = Snap.parseTransformString = function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (is(TString, "array") && is(TString[0], "array")) { // rough assumption + data = Snap.path.clone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b].concat(params)); + }); + } + data.toString = Snap.path.toString; + return data; +}; +function svgTransform2string(tstr) { + var res = []; + tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) { + params = params.split(/\s*,\s*|\s+/); + if (name == "rotate" && params.length == 1) { + params.push(0, 0); + } + if (name == "scale") { + if (params.length > 2) { + params = params.slice(0, 2); + } else if (params.length == 2) { + params.push(0, 0); + } + if (params.length == 1) { + params.push(params[0], 0, 0); + } + } + if (name == "skewX") { + res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]); + } else if (name == "skewY") { + res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]); + } else { + res.push([name.charAt(0)].concat(params)); + } + return all; + }); + return res; +} +Snap._.svgTransform2string = svgTransform2string; +Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i; +function transform2matrix(tstr, bbox) { + var tdata = parseTransformString(tstr), + m = new Snap.Matrix; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 2){ + m.translate(t[1], 0); + } else if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || bbox; + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || bbox; + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.scale(t[1], t[1], x2, y2); + } else { + m.scale(t[1], t[1], t[2], t[3]); + } + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + } + } + return m; +} +Snap._.transform2matrix = transform2matrix; +Snap._unit2px = unit2px; +var contains = glob.doc.contains || glob.doc.compareDocumentPosition ? + function (a, b) { + var adown = a.nodeType == 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a == bup || !!(bup && bup.nodeType == 1 && ( + adown.contains ? + adown.contains(bup) : + a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16 + )); + } : + function (a, b) { + if (b) { + while (b) { + b = b.parentNode; + if (b == a) { + return true; + } + } + } + return false; + }; +function getSomeDefs(el) { + var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) || + (el.node.parentNode && wrap(el.node.parentNode)) || + Snap.select("svg") || + Snap(0, 0), + pdefs = p.select("defs"), + defs = pdefs == null ? false : pdefs.node; + if (!defs) { + defs = make("defs", p.node).node; + } + return defs; +} +function getSomeSVG(el) { + return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg"); +} +Snap._.getSomeDefs = getSomeDefs; +Snap._.getSomeSVG = getSomeSVG; +function unit2px(el, name, value) { + var svg = getSomeSVG(el).node, + out = {}, + mgr = svg.querySelector(".svg---mgr"); + if (!mgr) { + mgr = $("rect"); + $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"}); + svg.appendChild(mgr); + } + function getW(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {width: val}); + try { + return mgr.getBBox().width; + } catch (e) { + return 0; + } + } + function getH(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {height: val}); + try { + return mgr.getBBox().height; + } catch (e) { + return 0; + } + } + function set(nam, f) { + if (name == null) { + out[nam] = f(el.attr(nam) || 0); + } else if (nam == name) { + out = f(value == null ? el.attr(nam) || 0 : value); + } + } + switch (el.type) { + case "rect": + set("rx", getW); + set("ry", getH); + case "image": + set("width", getW); + set("height", getH); + case "text": + set("x", getW); + set("y", getH); + break; + case "circle": + set("cx", getW); + set("cy", getH); + set("r", getW); + break; + case "ellipse": + set("cx", getW); + set("cy", getH); + set("rx", getW); + set("ry", getH); + break; + case "line": + set("x1", getW); + set("x2", getW); + set("y1", getH); + set("y2", getH); + break; + case "marker": + set("refX", getW); + set("markerWidth", getW); + set("refY", getH); + set("markerHeight", getH); + break; + case "radialGradient": + set("fx", getW); + set("fy", getH); + break; + case "tspan": + set("dx", getW); + set("dy", getH); + break; + default: + set(name, getW); + } + svg.removeChild(mgr); + return out; +} +/*\ + * Snap.select + [ method ] + ** + * Wraps a DOM element specified by CSS selector as @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.select = function (query) { + query = Str(query).replace(/([^\\]):/g, "$1\\:"); + return wrap(glob.doc.querySelector(query)); +}; +/*\ + * Snap.selectAll + [ method ] + ** + * Wraps DOM elements specified by CSS selector as set or array of @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.selectAll = function (query) { + var nodelist = glob.doc.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; +}; + +function add2group(list) { + if (!is(list, "array")) { + list = Array.prototype.slice.call(arguments, 0); + } + var i = 0, + j = 0, + node = this.node; + while (this[i]) delete this[i++]; + for (i = 0; i < list.length; i++) { + if (list[i].type == "set") { + list[i].forEach(function (el) { + node.appendChild(el.node); + }); + } else { + node.appendChild(list[i].node); + } + } + var children = node.childNodes; + for (i = 0; i < children.length; i++) { + this[j++] = wrap(children[i]); + } + return this; +} +// Hub garbage collector every 10s +setInterval(function () { + for (var key in hub) if (hub[has](key)) { + var el = hub[key], + node = el.node; + if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) { + delete hub[key]; + } + } +}, 1e4); +function Element(el) { + if (el.snap in hub) { + return hub[el.snap]; + } + var svg; + try { + svg = el.ownerSVGElement; + } catch(e) {} + /*\ + * Element.node + [ property (object) ] + ** + * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. + > Usage + | // draw a circle at coordinate 10,10 with radius of 10 + | var c = paper.circle(10, 10, 10); + | c.node.onclick = function () { + | c.attr("fill", "red"); + | }; + \*/ + this.node = el; + if (svg) { + this.paper = new Paper(svg); + } + /*\ + * Element.type + [ property (string) ] + ** + * SVG tag name of the given element. + \*/ + this.type = el.tagName || el.nodeName; + var id = this.id = ID(this); + this.anims = {}; + this._ = { + transform: [] + }; + el.snap = id; + hub[id] = this; + if (this.type == "g") { + this.add = add2group; + } + if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) { + for (var method in Paper.prototype) if (Paper.prototype[has](method)) { + this[method] = Paper.prototype[method]; + } + } +} + /*\ + * Element.attr + [ method ] + ** + * Gets or sets given attributes of the element. + ** + - params (object) contains key-value pairs of attributes you want to set + * or + - param (string) name of the attribute + = (Element) the current element + * or + = (string) value of attribute + > Usage + | el.attr({ + | fill: "#fc0", + | stroke: "#000", + | strokeWidth: 2, // CamelCase... + | "fill-opacity": 0.5, // or dash-separated names + | width: "*=2" // prefixed values + | }); + | console.log(el.attr("fill")); // #fc0 + * Prefixed values in format `"+=10"` supported. All four operations + * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+` + * and `-`: `"+=2em"`. + \*/ + Element.prototype.attr = function (params, value) { + var el = this, + node = el.node; + if (!params) { + if (node.nodeType != 1) { + return { + text: node.nodeValue + }; + } + var attr = node.attributes, + out = {}; + for (var i = 0, ii = attr.length; i < ii; i++) { + out[attr[i].nodeName] = attr[i].nodeValue; + } + return out; + } + if (is(params, "string")) { + if (arguments.length > 1) { + var json = {}; + json[params] = value; + params = json; + } else { + return eve("snap.util.getattr." + params, el).firstDefined(); + } + } + for (var att in params) { + if (params[has](att)) { + eve("snap.util.attr." + att, el, params[att]); + } + } + return el; + }; +/*\ + * Snap.parse + [ method ] + ** + * Parses SVG fragment and converts it into a @Fragment + ** + - svg (string) SVG string + = (Fragment) the @Fragment +\*/ +Snap.parse = function (svg) { + var f = glob.doc.createDocumentFragment(), + full = true, + div = glob.doc.createElement("div"); + svg = Str(svg); + if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) { + svg = "<svg>" + svg + "</svg>"; + full = false; + } + div.innerHTML = svg; + svg = div.getElementsByTagName("svg")[0]; + if (svg) { + if (full) { + f = svg; + } else { + while (svg.firstChild) { + f.appendChild(svg.firstChild); + } + } + } + return new Fragment(f); +}; +function Fragment(frag) { + this.node = frag; +} +/*\ + * Snap.fragment + [ method ] + ** + * Creates a DOM fragment from a given list of elements or strings + ** + - varargs (…) SVG string + = (Fragment) the @Fragment +\*/ +Snap.fragment = function () { + var args = Array.prototype.slice.call(arguments, 0), + f = glob.doc.createDocumentFragment(); + for (var i = 0, ii = args.length; i < ii; i++) { + var item = args[i]; + if (item.node && item.node.nodeType) { + f.appendChild(item.node); + } + if (item.nodeType) { + f.appendChild(item); + } + if (typeof item == "string") { + f.appendChild(Snap.parse(item).node); + } + } + return new Fragment(f); +}; + +function make(name, parent) { + var res = $(name); + parent.appendChild(res); + var el = wrap(res); + return el; +} +function Paper(w, h) { + var res, + desc, + defs, + proto = Paper.prototype; + if (w && w.tagName == "svg") { + if (w.snap in hub) { + return hub[w.snap]; + } + var doc = w.ownerDocument; + res = new Element(w); + desc = w.getElementsByTagName("desc")[0]; + defs = w.getElementsByTagName("defs")[0]; + if (!desc) { + desc = $("desc"); + desc.appendChild(doc.createTextNode("Created with Snap")); + res.node.appendChild(desc); + } + if (!defs) { + defs = $("defs"); + res.node.appendChild(defs); + } + res.defs = defs; + for (var key in proto) if (proto[has](key)) { + res[key] = proto[key]; + } + res.paper = res.root = res; + } else { + res = make("svg", glob.doc.body); + $(res.node, { + height: h, + version: 1.1, + width: w, + xmlns: xmlns + }); + } + return res; +} +function wrap(dom) { + if (!dom) { + return dom; + } + if (dom instanceof Element || dom instanceof Fragment) { + return dom; + } + if (dom.tagName && dom.tagName.toLowerCase() == "svg") { + return new Paper(dom); + } + if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") { + return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]); + } + return new Element(dom); +} + +Snap._.make = make; +Snap._.wrap = wrap; +/*\ + * Paper.el + [ method ] + ** + * Creates an element on paper with a given name and no attributes + ** + - name (string) tag name + - attr (object) attributes + = (Element) the current element + > Usage + | var c = paper.circle(10, 10, 10); // is the same as... + | var c = paper.el("circle").attr({ + | cx: 10, + | cy: 10, + | r: 10 + | }); + | // and the same as + | var c = paper.el("circle", { + | cx: 10, + | cy: 10, + | r: 10 + | }); +\*/ +Paper.prototype.el = function (name, attr) { + var el = make(name, this.node); + attr && el.attr(attr); + return el; +}; +/*\ + * Element.children + [ method ] + ** + * Returns array of all the children of the element. + = (array) array of Elements +\*/ +Element.prototype.children = function () { + var out = [], + ch = this.node.childNodes; + for (var i = 0, ii = ch.length; i < ii; i++) { + out[i] = Snap(ch[i]); + } + return out; +}; +function jsonFiller(root, o) { + for (var i = 0, ii = root.length; i < ii; i++) { + var item = { + type: root[i].type, + attr: root[i].attr() + }, + children = root[i].children(); + o.push(item); + if (children.length) { + jsonFiller(children, item.childNodes = []); + } + } +} +/*\ + * Element.toJSON + [ method ] + ** + * Returns object representation of the given element and all its children. + = (object) in format + o { + o type (string) this.type, + o attr (object) attributes map, + o childNodes (array) optional array of children in the same format + o } +\*/ +Element.prototype.toJSON = function () { + var out = []; + jsonFiller([this], out); + return out[0]; +}; +// default +eve.on("snap.util.getattr", function () { + var att = eve.nt(); + att = att.substring(att.lastIndexOf(".") + 1); + var css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css); + } else { + return $(this.node, att); + } +}); +var cssAttr = { + "alignment-baseline": 0, + "baseline-shift": 0, + "clip": 0, + "clip-path": 0, + "clip-rule": 0, + "color": 0, + "color-interpolation": 0, + "color-interpolation-filters": 0, + "color-profile": 0, + "color-rendering": 0, + "cursor": 0, + "direction": 0, + "display": 0, + "dominant-baseline": 0, + "enable-background": 0, + "fill": 0, + "fill-opacity": 0, + "fill-rule": 0, + "filter": 0, + "flood-color": 0, + "flood-opacity": 0, + "font": 0, + "font-family": 0, + "font-size": 0, + "font-size-adjust": 0, + "font-stretch": 0, + "font-style": 0, + "font-variant": 0, + "font-weight": 0, + "glyph-orientation-horizontal": 0, + "glyph-orientation-vertical": 0, + "image-rendering": 0, + "kerning": 0, + "letter-spacing": 0, + "lighting-color": 0, + "marker": 0, + "marker-end": 0, + "marker-mid": 0, + "marker-start": 0, + "mask": 0, + "opacity": 0, + "overflow": 0, + "pointer-events": 0, + "shape-rendering": 0, + "stop-color": 0, + "stop-opacity": 0, + "stroke": 0, + "stroke-dasharray": 0, + "stroke-dashoffset": 0, + "stroke-linecap": 0, + "stroke-linejoin": 0, + "stroke-miterlimit": 0, + "stroke-opacity": 0, + "stroke-width": 0, + "text-anchor": 0, + "text-decoration": 0, + "text-rendering": 0, + "unicode-bidi": 0, + "visibility": 0, + "word-spacing": 0, + "writing-mode": 0 +}; + +eve.on("snap.util.attr", function (value) { + var att = eve.nt(), + attr = {}; + att = att.substring(att.lastIndexOf(".") + 1); + attr[att] = value; + var style = att.replace(/-(\w)/gi, function (all, letter) { + return letter.toUpperCase(); + }), + css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + this.node.style[style] = value == null ? E : value; + } else { + $(this.node, attr); + } +}); +(function (proto) {}(Paper.prototype)); + +// simple ajax +/*\ + * Snap.ajax + [ method ] + ** + * Simple implementation of Ajax + ** + - url (string) URL + - postData (object|string) data for post request + - callback (function) callback + - scope (object) #optional scope of callback + * or + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback + = (XMLHttpRequest) the XMLHttpRequest object, just in case +\*/ +Snap.ajax = function (url, postData, callback, scope){ + var req = new XMLHttpRequest, + id = ID(); + if (req) { + if (is(postData, "function")) { + scope = callback; + callback = postData; + postData = null; + } else if (is(postData, "object")) { + var pd = []; + for (var key in postData) if (postData.hasOwnProperty(key)) { + pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key])); + } + postData = pd.join("&"); + } + req.open((postData ? "POST" : "GET"), url, true); + if (postData) { + req.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + if (callback) { + eve.once("snap.ajax." + id + ".0", callback); + eve.once("snap.ajax." + id + ".200", callback); + eve.once("snap.ajax." + id + ".304", callback); + } + req.onreadystatechange = function() { + if (req.readyState != 4) return; + eve("snap.ajax." + id + "." + req.status, scope, req); + }; + if (req.readyState == 4) { + return req; + } + req.send(postData); + return req; + } +}; +/*\ + * Snap.load + [ method ] + ** + * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX) + ** + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback +\*/ +Snap.load = function (url, callback, scope) { + Snap.ajax(url, function (req) { + var f = Snap.parse(req.responseText); + scope ? callback.call(scope, f) : callback(f); + }); +}; +var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; +}; +/*\ + * Snap.getElementByPoint + [ method ] + ** + * Returns you topmost element under given point. + ** + = (object) Snap element object + - x (number) x coordinate from the top left corner of the window + - y (number) y coordinate from the top left corner of the window + > Usage + | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); +\*/ +Snap.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = glob.doc.elementFromPoint(x, y); + if (glob.win.opera && target.tagName == "svg") { + var so = getOffset(target), + sr = target.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = target.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + return wrap(target); +}; +/*\ + * Snap.plugin + [ method ] + ** + * Let you write plugins. You pass in a function with five arguments, like this: + | Snap.plugin(function (Snap, Element, Paper, global, Fragment) { + | Snap.newmethod = function () {}; + | Element.prototype.newmethod = function () {}; + | Paper.prototype.newmethod = function () {}; + | }); + * Inside the function you have access to all main objects (and their + * prototypes). This allow you to extend anything you want. + ** + - f (function) your plugin body +\*/ +Snap.plugin = function (f) { + f(Snap, Element, Paper, glob, Fragment); +}; +glob.win.Snap = Snap; +return Snap; +}(window || this)); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var elproto = Element.prototype, + is = Snap.is, + Str = String, + unit2px = Snap._unit2px, + $ = Snap._.$, + make = Snap._.make, + getSomeDefs = Snap._.getSomeDefs, + has = "hasOwnProperty", + wrap = Snap._.wrap; + /*\ + * Element.getBBox + [ method ] + ** + * Returns the bounding box descriptor for the given element + ** + = (object) bounding box descriptor: + o { + o cx: (number) x of the center, + o cy: (number) x of the center, + o h: (number) height, + o height: (number) height, + o path: (string) path command for the box, + o r0: (number) radius of a circle that fully encloses the box, + o r1: (number) radius of the smallest circle that can be enclosed, + o r2: (number) radius of the largest circle that can be enclosed, + o vb: (string) box as a viewbox command, + o w: (number) width, + o width: (number) width, + o x2: (number) x of the right side, + o x: (number) x of the left side, + o y2: (number) y of the bottom edge, + o y: (number) y of the top edge + o } + \*/ + elproto.getBBox = function (isWithoutTransform) { + if (!Snap.Matrix || !Snap.path) { + return this.node.getBBox(); + } + var el = this, + m = new Snap.Matrix; + if (el.removed) { + return Snap._.box(); + } + while (el.type == "use") { + if (!isWithoutTransform) { + m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0)); + } + if (el.original) { + el = el.original; + } else { + var href = el.attr("xlink:href"); + el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1)); + } + } + var _ = el._, + pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt; + try { + if (isWithoutTransform) { + _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox()); + return Snap._.box(_.bboxwt); + } else { + el.realPath = pathfinder(el); + el.matrix = el.transform().localMatrix; + _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix))); + return Snap._.box(_.bbox); + } + } catch (e) { + // Firefox doesn’t give you bbox of hidden element + return Snap._.box(); + } + }; + var propString = function () { + return this.string; + }; + function extractTransform(el, tstr) { + if (tstr == null) { + var doReturn = true; + if (el.type == "linearGradient" || el.type == "radialGradient") { + tstr = el.node.getAttribute("gradientTransform"); + } else if (el.type == "pattern") { + tstr = el.node.getAttribute("patternTransform"); + } else { + tstr = el.node.getAttribute("transform"); + } + if (!tstr) { + return new Snap.Matrix; + } + tstr = Snap._.svgTransform2string(tstr); + } else { + if (!Snap._.rgTransform.test(tstr)) { + tstr = Snap._.svgTransform2string(tstr); + } else { + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || ""); + } + if (is(tstr, "array")) { + tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr); + } + el._.transform = tstr; + } + var m = Snap._.transform2matrix(tstr, el.getBBox(1)); + if (doReturn) { + return m; + } else { + el.matrix = m; + } + } + /*\ + * Element.transform + [ method ] + ** + * Gets or sets transformation of the element + ** + - tstr (string) transform string in Snap or SVG format + = (Element) the current element + * or + = (object) transformation descriptor: + o { + o string (string) transform string, + o globalMatrix (Matrix) matrix of all transformations applied to element or its parents, + o localMatrix (Matrix) matrix of transformations applied only to the element, + o diffMatrix (Matrix) matrix of difference between global and local transformations, + o global (string) global transformation as string, + o local (string) local transformation as string, + o toString (function) returns `string` property + o } + \*/ + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + var papa = this, + global = new Snap.Matrix(this.node.getCTM()), + local = extractTransform(this), + ms = [local], + m = new Snap.Matrix, + i, + localString = local.toTransformString(), + string = Str(local) == Str(this.matrix) ? + Str(_.transform) : localString; + while (papa.type != "svg" && (papa = papa.parent())) { + ms.push(extractTransform(papa)); + } + i = ms.length; + while (i--) { + m.add(ms[i]); + } + return { + string: string, + globalMatrix: global, + totalMatrix: m, + localMatrix: local, + diffMatrix: global.clone().add(local.invert()), + global: global.toTransformString(), + total: m.toTransformString(), + local: localString, + toString: propString + }; + } + if (tstr instanceof Snap.Matrix) { + this.matrix = tstr; + this._.transform = tstr.toTransformString(); + } else { + extractTransform(this, tstr); + } + + if (this.node) { + if (this.type == "linearGradient" || this.type == "radialGradient") { + $(this.node, {gradientTransform: this.matrix}); + } else if (this.type == "pattern") { + $(this.node, {patternTransform: this.matrix}); + } else { + $(this.node, {transform: this.matrix}); + } + } + + return this; + }; + /*\ + * Element.parent + [ method ] + ** + * Returns the element's parent + ** + = (Element) the parent element + \*/ + elproto.parent = function () { + return wrap(this.node.parentNode); + }; + /*\ + * Element.append + [ method ] + ** + * Appends the given element to current one + ** + - el (Element|Set) element to append + = (Element) the parent element + \*/ + /*\ + * Element.add + [ method ] + ** + * See @Element.append + \*/ + elproto.append = elproto.add = function (el) { + if (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + it.add(el); + }); + return this; + } + el = wrap(el); + this.node.appendChild(el.node); + el.paper = this.paper; + } + return this; + }; + /*\ + * Element.appendTo + [ method ] + ** + * Appends the current element to the given one + ** + - el (Element) parent element to append to + = (Element) the child element + \*/ + elproto.appendTo = function (el) { + if (el) { + el = wrap(el); + el.append(this); + } + return this; + }; + /*\ + * Element.prepend + [ method ] + ** + * Prepends the given element to the current one + ** + - el (Element) element to prepend + = (Element) the parent element + \*/ + elproto.prepend = function (el) { + if (el) { + if (el.type == "set") { + var it = this, + first; + el.forEach(function (el) { + if (first) { + first.after(el); + } else { + it.prepend(el); + } + first = el; + }); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.insertBefore(el.node, this.node.firstChild); + this.add && this.add(); + el.paper = this.paper; + this.parent() && this.parent().add(); + parent && parent.add(); + } + return this; + }; + /*\ + * Element.prependTo + [ method ] + ** + * Prepends the current element to the given one + ** + - el (Element) parent element to prepend to + = (Element) the child element + \*/ + elproto.prependTo = function (el) { + el = wrap(el); + el.prepend(this); + return this; + }; + /*\ + * Element.before + [ method ] + ** + * Inserts given element before the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.before = function (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + var parent = el.parent(); + it.node.parentNode.insertBefore(el.node, it.node); + parent && parent.add(); + }); + this.parent().add(); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.parentNode.insertBefore(el.node, this.node); + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.after + [ method ] + ** + * Inserts given element after the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.after = function (el) { + el = wrap(el); + var parent = el.parent(); + if (this.node.nextSibling) { + this.node.parentNode.insertBefore(el.node, this.node.nextSibling); + } else { + this.node.parentNode.appendChild(el.node); + } + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.insertBefore + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertBefore = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.insertAfter + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertAfter = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node.nextSibling); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.remove + [ method ] + ** + * Removes element from the DOM + = (Element) the detached element + \*/ + elproto.remove = function () { + var parent = this.parent(); + this.node.parentNode && this.node.parentNode.removeChild(this.node); + delete this.paper; + this.removed = true; + parent && parent.add(); + return this; + }; + /*\ + * Element.select + [ method ] + ** + * Gathers the nested @Element matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Element) result of query selection + \*/ + elproto.select = function (query) { + return wrap(this.node.querySelector(query)); + }; + /*\ + * Element.selectAll + [ method ] + ** + * Gathers nested @Element objects matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Set|array) result of query selection + \*/ + elproto.selectAll = function (query) { + var nodelist = this.node.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; + }; + /*\ + * Element.asPX + [ method ] + ** + * Returns given attribute of the element as a `px` value (not %, em, etc.) + ** + - attr (string) attribute name + - value (string) #optional attribute value + = (Element) result of query selection + \*/ + elproto.asPX = function (attr, value) { + if (value == null) { + value = this.attr(attr); + } + return +unit2px(this, attr, value); + }; + // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar. + /*\ + * Element.use + [ method ] + ** + * Creates a `<use>` element linked to the current element + ** + = (Element) the `<use>` element + \*/ + elproto.use = function () { + var use, + id = this.node.id; + if (!id) { + id = this.id; + $(this.node, { + id: id + }); + } + if (this.type == "linearGradient" || this.type == "radialGradient" || + this.type == "pattern") { + use = make(this.type, this.node.parentNode); + } else { + use = make("use", this.node.parentNode); + } + $(use.node, { + "xlink:href": "#" + id + }); + use.original = this; + return use; + }; + function fixids(el) { + var els = el.selectAll("*"), + it, + url = /^\s*url\(("|'|)(.*)\1\)\s*$/, + ids = [], + uses = {}; + function urltest(it, name) { + var val = $(it.node, name); + val = val && val.match(url); + val = val && val[2]; + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + var attr = {}; + attr[name] = URL(id); + $(it.node, attr); + }); + } + } + function linktest(it) { + var val = $(it.node, "xlink:href"); + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + it.attr("xlink:href", "#" + id); + }); + } + } + for (var i = 0, ii = els.length; i < ii; i++) { + it = els[i]; + urltest(it, "fill"); + urltest(it, "stroke"); + urltest(it, "filter"); + urltest(it, "mask"); + urltest(it, "clip-path"); + linktest(it); + var oldid = $(it.node, "id"); + if (oldid) { + $(it.node, {id: it.id}); + ids.push({ + old: oldid, + id: it.id + }); + } + } + for (i = 0, ii = ids.length; i < ii; i++) { + var fs = uses[ids[i].old]; + if (fs) { + for (var j = 0, jj = fs.length; j < jj; j++) { + fs[j](ids[i].id); + } + } + } + } + /*\ + * Element.clone + [ method ] + ** + * Creates a clone of the element and inserts it after the element + ** + = (Element) the clone + \*/ + elproto.clone = function () { + var clone = wrap(this.node.cloneNode(true)); + if ($(clone.node, "id")) { + $(clone.node, {id: clone.id}); + } + fixids(clone); + clone.insertAfter(this); + return clone; + }; + /*\ + * Element.toDefs + [ method ] + ** + * Moves element to the shared `<defs>` area + ** + = (Element) the element + \*/ + elproto.toDefs = function () { + var defs = getSomeDefs(this); + defs.appendChild(this.node); + return this; + }; + /*\ + * Element.toPattern + [ method ] + ** + * Creates a `<pattern>` element from the current element + ** + * To create a pattern you have to specify the pattern rect: + - x (string|number) + - y (string|number) + - width (string|number) + - height (string|number) + = (Element) the `<pattern>` element + * You can use pattern later on as an argument for `fill` attribute: + | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({ + | fill: "none", + | stroke: "#bada55", + | strokeWidth: 5 + | }).pattern(0, 0, 10, 10), + | c = paper.circle(200, 200, 100); + | c.attr({ + | fill: p + | }); + \*/ + elproto.pattern = elproto.toPattern = function (x, y, width, height) { + var p = make("pattern", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + $(p.node, { + x: x, + y: y, + width: width, + height: height, + patternUnits: "userSpaceOnUse", + id: p.id, + viewBox: [x, y, width, height].join(" ") + }); + p.node.appendChild(this.node); + return p; + }; +// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path. +// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values? + /*\ + * Element.marker + [ method ] + ** + * Creates a `<marker>` element from the current element + ** + * To create a marker you have to specify the bounding rect and reference point: + - x (number) + - y (number) + - width (number) + - height (number) + - refX (number) + - refY (number) + = (Element) the `<marker>` element + * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end. + \*/ + // TODO add usage for markers + elproto.marker = function (x, y, width, height, refX, refY) { + var p = make("marker", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + refX = x.refX || x.cx; + refY = x.refY || x.cy; + x = x.x; + } + $(p.node, { + viewBox: [x, y, width, height].join(" "), + markerWidth: width, + markerHeight: height, + orient: "auto", + refX: refX || 0, + refY: refY || 0, + id: p.id + }); + p.node.appendChild(this.node); + return p; + }; + // animation + function slice(from, to, f) { + return function (arr) { + var res = arr.slice(from, to); + if (res.length == 1) { + res = res[0]; + } + return f ? f(res) : res; + }; + } + var Animation = function (attr, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + this.attr = attr; + this.dur = ms; + easing && (this.easing = easing); + callback && (this.callback = callback); + }; + Snap._.Animation = Animation; + /*\ + * Snap.animation + [ method ] + ** + * Creates an animation object + ** + - attr (object) attributes of final destination + - duration (number) duration of the animation, in milliseconds + - easing (function) #optional one of easing functions of @mina or custom one + - callback (function) #optional callback function that fires when animation ends + = (object) animation object + \*/ + Snap.animation = function (attr, ms, easing, callback) { + return new Animation(attr, ms, easing, callback); + }; + /*\ + * Element.inAnim + [ method ] + ** + * Returns a set of animations that may be able to manipulate the current element + ** + = (object) in format: + o { + o anim (object) animation object, + o mina (object) @mina object, + o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + \*/ + elproto.inAnim = function () { + var el = this, + res = []; + for (var id in el.anims) if (el.anims[has](id)) { + (function (a) { + res.push({ + anim: new Animation(a._attrs, a.dur, a.easing, a._callback), + mina: a, + curStatus: a.status(), + status: function (val) { + return a.status(val); + }, + stop: function () { + a.stop(); + } + }); + }(el.anims[id])); + } + return res; + }; + /*\ + * Snap.animate + [ method ] + ** + * Runs generic animation of one number into another with a caring function + ** + - from (number|array) number or array of numbers + - to (number|array) number or array of numbers + - setter (function) caring function that accepts one number argument + - duration (number) duration, in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function to execute when animation ends + = (object) animation object in @mina format + o { + o id (string) animation id, consider it read-only, + o duration (function) gets or sets the duration of the animation, + o easing (function) easing, + o speed (function) gets or sets the speed of the animation, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + | var rect = Snap().rect(0, 0, 10, 10); + | Snap.animate(0, 10, function (val) { + | rect.attr({ + | x: val + | }); + | }, 1000); + | // in given context is equivalent to + | rect.animate({x: 10}, 1000); + \*/ + Snap.animate = function (from, to, setter, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + var now = mina.time(), + anim = mina(from, to, now, now + ms, mina.time, setter, easing); + callback && eve.once("mina.finish." + anim.id, callback); + return anim; + }; + /*\ + * Element.stop + [ method ] + ** + * Stops all the animations for the current element + ** + = (Element) the current element + \*/ + elproto.stop = function () { + var anims = this.inAnim(); + for (var i = 0, ii = anims.length; i < ii; i++) { + anims[i].stop(); + } + return this; + }; + /*\ + * Element.animate + [ method ] + ** + * Animates the given attributes of the element + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + = (Element) the current element + \*/ + elproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = attrs.dur; + attrs = attrs.attr; + } + var fkeys = [], tkeys = [], keys = {}, from, to, f, eq, + el = this; + for (var key in attrs) if (attrs[has](key)) { + if (el.equal) { + eq = el.equal(key, Str(attrs[key])); + from = eq.from; + to = eq.to; + f = eq.f; + } else { + from = +el.attr(key); + to = +attrs[key]; + } + var len = is(from, "array") ? from.length : 1; + keys[key] = slice(fkeys.length, fkeys.length + len, f); + fkeys = fkeys.concat(from); + tkeys = tkeys.concat(to); + } + var now = mina.time(), + anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) { + var attr = {}; + for (var key in keys) if (keys[has](key)) { + attr[key] = keys[key](val); + } + el.attr(attr); + }, easing); + el.anims[anim.id] = anim; + anim._attrs = attrs; + anim._callback = callback; + eve("snap.animcreated." + el.id, anim); + eve.once("mina.finish." + anim.id, function () { + delete el.anims[anim.id]; + callback && callback.call(el); + }); + eve.once("mina.stop." + anim.id, function () { + delete el.anims[anim.id]; + }); + return el; + }; + var eldata = {}; + /*\ + * Element.data + [ method ] + ** + * Adds or retrieves given value associated with given key. (Don’t confuse + * with `data-` attributes) + * + * See also @Element.removeData + - key (string) key to store data + - value (any) #optional value to store + = (object) @Element + * or, if value is not specified: + = (any) value + > Usage + | for (var i = 0, i < 5, i++) { + | paper.circle(10 + 15 * i, 10, 10) + | .attr({fill: "#000"}) + | .data("i", i) + | .click(function () { + | alert(this.data("i")); + | }); + | } + \*/ + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 0){ + eve("snap.data.get." + this.id, this, data, null); + return data; + } + if (arguments.length == 1) { + if (Snap.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("snap.data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("snap.data.set." + this.id, this, value, key); + return this; + }; + /*\ + * Element.removeData + [ method ] + ** + * Removes value associated with an element by given key. + * If key is not provided, removes all the data of the element. + - key (string) #optional key + = (object) @Element + \*/ + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + /*\ + * Element.outerSVG + [ method ] + ** + * Returns SVG code for the element, equivalent to HTML's `outerHTML`. + * + * See also @Element.innerSVG + = (string) SVG code for the element + \*/ + /*\ + * Element.toString + [ method ] + ** + * See @Element.outerSVG + \*/ + elproto.outerSVG = elproto.toString = toString(1); + /*\ + * Element.innerSVG + [ method ] + ** + * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML` + = (string) SVG code for the element + \*/ + elproto.innerSVG = toString(); + function toString(type) { + return function () { + var res = type ? "<" + this.type : "", + attr = this.node.attributes, + chld = this.node.childNodes; + if (type) { + for (var i = 0, ii = attr.length; i < ii; i++) { + res += " " + attr[i].name + '="' + + attr[i].value.replace(/"/g, '\\"') + '"'; + } + } + if (chld.length) { + type && (res += ">"); + for (i = 0, ii = chld.length; i < ii; i++) { + if (chld[i].nodeType == 3) { + res += chld[i].nodeValue; + } else if (chld[i].nodeType == 1) { + res += wrap(chld[i]).toString(); + } + } + type && (res += "</" + this.type + ">"); + } else { + type && (res += "/>"); + } + return res; + }; + } + elproto.toDataURL = function () { + if (window && window.btoa) { + var bb = this.getBBox(), + svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', { + x: +bb.x.toFixed(3), + y: +bb.y.toFixed(3), + width: +bb.width.toFixed(3), + height: +bb.height.toFixed(3), + contents: this.outerSVG() + }); + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg))); + } + }; + /*\ + * Fragment.select + [ method ] + ** + * See @Element.select + \*/ + Fragment.prototype.select = elproto.select; + /*\ + * Fragment.selectAll + [ method ] + ** + * See @Element.selectAll + \*/ + Fragment.prototype.selectAll = elproto.selectAll; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var objectToString = Object.prototype.toString, + Str = String, + math = Math, + E = ""; + function Matrix(a, b, c, d, e, f) { + if (b == null && objectToString.call(a) == "[object SVGMatrix]") { + this.a = a.a; + this.b = a.b; + this.c = a.c; + this.d = a.d; + this.e = a.e; + this.f = a.f; + return; + } + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + /*\ + * Matrix.add + [ method ] + ** + * Adds the given matrix to existing one + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - matrix (object) @Matrix + \*/ + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + return this; + }; + /*\ + * Matrix.invert + [ method ] + ** + * Returns an inverted version of the matrix + = (object) @Matrix + \*/ + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + /*\ + * Matrix.clone + [ method ] + ** + * Returns a copy of the matrix + = (object) @Matrix + \*/ + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + /*\ + * Matrix.translate + [ method ] + ** + * Translate the matrix + - x (number) horizontal offset distance + - y (number) vertical offset distance + \*/ + matrixproto.translate = function (x, y) { + return this.add(1, 0, 0, 1, x, y); + }; + /*\ + * Matrix.scale + [ method ] + ** + * Scales the matrix + - x (number) amount to be scaled, with `1` resulting in no change + - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.) + - cx (number) #optional horizontal origin point from which to scale + - cy (number) #optional vertical origin point from which to scale + * Default cx, cy is the middle point of the element. + \*/ + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + return this; + }; + /*\ + * Matrix.rotate + [ method ] + ** + * Rotates the matrix + - a (number) angle of rotation, in degrees + - x (number) horizontal origin point from which to rotate + - y (number) vertical origin point from which to rotate + \*/ + matrixproto.rotate = function (a, x, y) { + a = Snap.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + return this.add(1, 0, 0, 1, -x, -y); + }; + /*\ + * Matrix.x + [ method ] + ** + * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y + - x (number) + - y (number) + = (number) x + \*/ + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + /*\ + * Matrix.y + [ method ] + ** + * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x + - x (number) + - y (number) + = (number) y + \*/ + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + /*\ + * Matrix.determinant + [ method ] + ** + * Finds determinant of the given matrix. + = (number) determinant + \*/ + matrixproto.determinant = function () { + return this.a * this.d - this.b * this.c; + }; + /*\ + * Matrix.split + [ method ] + ** + * Splits matrix into primitive transformations + = (object) in format: + o dx (number) translation by x + o dy (number) translation by y + o scalex (number) scale by x + o scaley (number) scale by y + o shear (number) shear + o rotate (number) rotation in deg + o isSimple (boolean) could it be represented via simple transformations + \*/ + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + if (this.determinant() < 0) { + out.scalex = -out.scalex; + } + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = Snap.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = Snap.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + /*\ + * Matrix.toTransformString + [ method ] + ** + * Returns transform string that represents given matrix + = (string) transform string + \*/ + matrixproto.toTransformString = function (shorter) { + var s = shorter || this.split(); + if (!+s.shear.toFixed(9)) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + /*\ + * Snap.Matrix + [ method ] + ** + * Matrix constructor, extend on your own risk. + * To create matrices use @Snap.matrix. + \*/ + Snap.Matrix = Matrix; + /*\ + * Snap.matrix + [ method ] + ** + * Utility method + ** + * Returns a matrix based on the given parameters + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - svgMatrix (SVGMatrix) + = (object) @Matrix + \*/ + Snap.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var has = "hasOwnProperty", + make = Snap._.make, + wrap = Snap._.wrap, + is = Snap.is, + getSomeDefs = Snap._.getSomeDefs, + reURLValue = /^url\(#?([^)]+)\)$/, + $ = Snap._.$, + URL = Snap.url, + Str = String, + separator = Snap._.separator, + E = ""; + // Attributes event handlers + eve.on("snap.util.attr.mask", function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value.type == "mask") { + var mask = value; + } else { + mask = make("mask", getSomeDefs(this)); + mask.node.appendChild(value.node); + } + !mask.node.id && $(mask.node, { + id: mask.id + }); + $(this.node, { + mask: URL(mask.id) + }); + } + }); + (function (clipIt) { + eve.on("snap.util.attr.clip", clipIt); + eve.on("snap.util.attr.clip-path", clipIt); + eve.on("snap.util.attr.clipPath", clipIt); + }(function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value.type == "clipPath") { + var clip = value; + } else { + clip = make("clipPath", getSomeDefs(this)); + clip.node.appendChild(value.node); + !clip.node.id && $(clip.node, { + id: clip.id + }); + } + $(this.node, { + "clip-path": URL(clip.node.id || clip.id) + }); + } + })); + function fillStroke(name) { + return function (value) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1 && + (value.node.firstChild.tagName == "radialGradient" || + value.node.firstChild.tagName == "linearGradient" || + value.node.firstChild.tagName == "pattern")) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value instanceof Element) { + if (value.type == "radialGradient" || value.type == "linearGradient" + || value.type == "pattern") { + if (!value.node.id) { + $(value.node, { + id: value.id + }); + } + var fill = URL(value.node.id); + } else { + fill = value.attr(name); + } + } else { + fill = Snap.color(value); + if (fill.error) { + var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value); + if (grad) { + if (!grad.node.id) { + $(grad.node, { + id: grad.id + }); + } + fill = URL(grad.node.id); + } else { + fill = value; + } + } else { + fill = Str(fill); + } + } + var attrs = {}; + attrs[name] = fill; + $(this.node, attrs); + this.node.style[name] = E; + }; + } + eve.on("snap.util.attr.fill", fillStroke("fill")); + eve.on("snap.util.attr.stroke", fillStroke("stroke")); + var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i; + eve.on("snap.util.grad.parse", function parseGrad(string) { + string = Str(string); + var tokens = string.match(gradrg); + if (!tokens) { + return null; + } + var type = tokens[1], + params = tokens[2], + stops = tokens[3]; + params = params.split(/\s*,\s*/).map(function (el) { + return +el == el ? +el : el; + }); + if (params.length == 1 && params[0] == 0) { + params = []; + } + stops = stops.split("-"); + stops = stops.map(function (el) { + el = el.split(":"); + var out = { + color: el[0] + }; + if (el[1]) { + out.offset = parseFloat(el[1]); + } + return out; + }); + return { + type: type, + params: params, + stops: stops + }; + }); + + eve.on("snap.util.attr.d", function (value) { + eve.stop(); + if (is(value, "array") && is(value[0], "array")) { + value = Snap.path.toString.call(value); + } + value = Str(value); + if (value.match(/[ruo]/i)) { + value = Snap.path.toAbsolute(value); + } + $(this.node, {d: value}); + })(-1); + eve.on("snap.util.attr.#text", function (value) { + eve.stop(); + value = Str(value); + var txt = glob.doc.createTextNode(value); + while (this.node.firstChild) { + this.node.removeChild(this.node.firstChild); + } + this.node.appendChild(txt); + })(-1); + eve.on("snap.util.attr.path", function (value) { + eve.stop(); + this.attr({d: value}); + })(-1); + eve.on("snap.util.attr.class", function (value) { + eve.stop(); + this.node.className.baseVal = value; + })(-1); + eve.on("snap.util.attr.viewBox", function (value) { + var vb; + if (is(value, "object") && "x" in value) { + vb = [value.x, value.y, value.width, value.height].join(" "); + } else if (is(value, "array")) { + vb = value.join(" "); + } else { + vb = value; + } + $(this.node, { + viewBox: vb + }); + eve.stop(); + })(-1); + eve.on("snap.util.attr.transform", function (value) { + this.transform(value); + eve.stop(); + })(-1); + eve.on("snap.util.attr.r", function (value) { + if (this.type == "rect") { + eve.stop(); + $(this.node, { + rx: value, + ry: value + }); + } + })(-1); + eve.on("snap.util.attr.textpath", function (value) { + eve.stop(); + if (this.type == "text") { + var id, tp, node; + if (!value && this.textPath) { + tp = this.textPath; + while (tp.node.firstChild) { + this.node.appendChild(tp.node.firstChild); + } + tp.remove(); + delete this.textPath; + return; + } + if (is(value, "string")) { + var defs = getSomeDefs(this), + path = wrap(defs.parentNode).path(value); + defs.appendChild(path.node); + id = path.id; + path.attr({id: id}); + } else { + value = wrap(value); + if (value instanceof Element) { + id = value.attr("id"); + if (!id) { + id = value.id; + value.attr({id: id}); + } + } + } + if (id) { + tp = this.textPath; + node = this.node; + if (tp) { + tp.attr({"xlink:href": "#" + id}); + } else { + tp = $("textPath", { + "xlink:href": "#" + id + }); + while (node.firstChild) { + tp.appendChild(node.firstChild); + } + node.appendChild(tp); + this.textPath = wrap(tp); + } + } + } + })(-1); + eve.on("snap.util.attr.text", function (value) { + if (this.type == "text") { + var i = 0, + node = this.node, + tuner = function (chunk) { + var out = $("tspan"); + if (is(chunk, "array")) { + for (var i = 0; i < chunk.length; i++) { + out.appendChild(tuner(chunk[i])); + } + } else { + out.appendChild(glob.doc.createTextNode(chunk)); + } + out.normalize && out.normalize(); + return out; + }; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var tuned = tuner(value); + while (tuned.firstChild) { + node.appendChild(tuned.firstChild); + } + } + eve.stop(); + })(-1); + function setFontSize(value) { + eve.stop(); + if (value == +value) { + value += "px"; + } + this.node.style.fontSize = value; + } + eve.on("snap.util.attr.fontSize", setFontSize)(-1); + eve.on("snap.util.attr.font-size", setFontSize)(-1); + + + eve.on("snap.util.getattr.transform", function () { + eve.stop(); + return this.transform(); + })(-1); + eve.on("snap.util.getattr.textpath", function () { + eve.stop(); + return this.textPath; + })(-1); + // Markers + (function () { + function getter(end) { + return function () { + eve.stop(); + var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end); + if (style == "none") { + return style; + } else { + return Snap(glob.doc.getElementById(style.match(reURLValue)[1])); + } + }; + } + function setter(end) { + return function (value) { + eve.stop(); + var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1); + if (value == "" || !value) { + this.node.style[name] = "none"; + return; + } + if (value.type == "marker") { + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + } + this.node.style[name] = URL(id); + return; + } + }; + } + eve.on("snap.util.getattr.marker-end", getter("end"))(-1); + eve.on("snap.util.getattr.markerEnd", getter("end"))(-1); + eve.on("snap.util.getattr.marker-start", getter("start"))(-1); + eve.on("snap.util.getattr.markerStart", getter("start"))(-1); + eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1); + eve.on("snap.util.getattr.markerMid", getter("mid"))(-1); + eve.on("snap.util.attr.marker-end", setter("end"))(-1); + eve.on("snap.util.attr.markerEnd", setter("end"))(-1); + eve.on("snap.util.attr.marker-start", setter("start"))(-1); + eve.on("snap.util.attr.markerStart", setter("start"))(-1); + eve.on("snap.util.attr.marker-mid", setter("mid"))(-1); + eve.on("snap.util.attr.markerMid", setter("mid"))(-1); + }()); + eve.on("snap.util.getattr.r", function () { + if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) { + eve.stop(); + return $(this.node, "rx"); + } + })(-1); + function textExtract(node) { + var out = []; + var children = node.childNodes; + for (var i = 0, ii = children.length; i < ii; i++) { + var chi = children[i]; + if (chi.nodeType == 3) { + out.push(chi.nodeValue); + } + if (chi.tagName == "tspan") { + if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) { + out.push(chi.firstChild.nodeValue); + } else { + out.push(textExtract(chi)); + } + } + } + return out; + } + eve.on("snap.util.getattr.text", function () { + if (this.type == "text" || this.type == "tspan") { + eve.stop(); + var out = textExtract(this.node); + return out.length == 1 ? out[0] : out; + } + })(-1); + eve.on("snap.util.getattr.#text", function () { + return this.node.textContent; + })(-1); + eve.on("snap.util.getattr.viewBox", function () { + eve.stop(); + var vb = $(this.node, "viewBox"); + if (vb) { + vb = vb.split(separator); + return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.points", function () { + var p = $(this.node, "points"); + eve.stop(); + if (p) { + return p.split(separator); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.path", function () { + var p = $(this.node, "d"); + eve.stop(); + return p; + })(-1); + eve.on("snap.util.getattr.class", function () { + return this.node.className.baseVal; + })(-1); + function getFontSize() { + eve.stop(); + return this.node.style.fontSize; + } + eve.on("snap.util.getattr.fontSize", getFontSize)(-1); + eve.on("snap.util.getattr.font-size", getFontSize)(-1); +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var rgNotSpace = /\S+/g, + rgBadSpace = /[\t\r\n\f]/g, + rgTrim = /(^\s+|\s+$)/g, + Str = String, + elproto = Element.prototype; + /*\ + * Element.addClass + [ method ] + ** + * Adds given class name or list of class names to the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.addClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + + if (classes.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (!~pos) { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.removeClass + [ method ] + ** + * Removes given class name or list of class names from the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.removeClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + if (curClasses.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.hasClass + [ method ] + ** + * Checks if the element has a given class name in the list of class names applied to it. + - value (string) class name + ** + = (boolean) `true` if the element has given class + \*/ + elproto.hasClass = function (value) { + var elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || []; + return !!~curClasses.indexOf(value); + }; + /*\ + * Element.toggleClass + [ method ] + ** + * Add or remove one or more classes from the element, depending on either + * the class’s presence or the value of the `flag` argument. + - value (string) class name or space separated list of class names + - flag (boolean) value to determine whether the class should be added or removed + ** + = (Element) original element. + \*/ + elproto.toggleClass = function (value, flag) { + if (flag != null) { + if (flag) { + return this.addClass(value); + } else { + return this.removeClass(value); + } + } + var classes = (value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } else { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var operators = { + "+": function (x, y) { + return x + y; + }, + "-": function (x, y) { + return x - y; + }, + "/": function (x, y) { + return x / y; + }, + "*": function (x, y) { + return x * y; + } + }, + Str = String, + reUnit = /[a-z]+$/i, + reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/; + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + eve.on("snap.util.attr", function (val) { + var plus = Str(val).match(reAddon); + if (plus) { + var evnt = eve.nt(), + name = evnt.substring(evnt.lastIndexOf(".") + 1), + a = this.attr(name), + atr = {}; + eve.stop(); + var unit = plus[3] || "", + aUnit = a.match(reUnit), + op = operators[plus[1]]; + if (aUnit && aUnit == unit) { + val = op(parseFloat(a), +plus[2]); + } else { + a = this.asPX(name); + val = op(this.asPX(name), this.asPX(name, plus[2] + unit)); + } + if (isNaN(a) || isNaN(val)) { + return; + } + atr[name] = val; + this.attr(atr); + } + })(-10); + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this, + bplus = Str(b).match(reAddon); + if (bplus) { + eve.stop(); + var unit = bplus[3] || "", + aUnit = a.match(reUnit), + op = operators[bplus[1]]; + if (aUnit && aUnit == unit) { + return { + from: parseFloat(a), + to: op(parseFloat(a), +bplus[2]), + f: getUnit(aUnit) + }; + } else { + a = this.asPX(name); + return { + from: a, + to: op(a, this.asPX(name, bplus[2] + unit)), + f: getNumber + }; + } + } + })(-10); +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var proto = Paper.prototype, + is = Snap.is; + /*\ + * Paper.rect + [ method ] + * + * Draws a rectangle + ** + - x (number) x coordinate of the top left corner + - y (number) y coordinate of the top left corner + - width (number) width + - height (number) height + - rx (number) #optional horizontal radius for rounded corners, default is 0 + - ry (number) #optional vertical radius for rounded corners, default is rx or 0 + = (object) the `rect` element + ** + > Usage + | // regular rectangle + | var c = paper.rect(10, 10, 50, 50); + | // rectangle with rounded corners + | var c = paper.rect(40, 40, 50, 50, 10); + \*/ + proto.rect = function (x, y, w, h, rx, ry) { + var attr; + if (ry == null) { + ry = rx; + } + if (is(x, "object") && x == "[object Object]") { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + width: w, + height: h + }; + if (rx != null) { + attr.rx = rx; + attr.ry = ry; + } + } + return this.el("rect", attr); + }; + /*\ + * Paper.circle + [ method ] + ** + * Draws a circle + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - r (number) radius + = (object) the `circle` element + ** + > Usage + | var c = paper.circle(50, 50, 40); + \*/ + proto.circle = function (cx, cy, r) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr = { + cx: cx, + cy: cy, + r: r + }; + } + return this.el("circle", attr); + }; + + var preload = (function () { + function onerror() { + this.parentNode.removeChild(this); + } + return function (src, f) { + var img = glob.doc.createElement("img"), + body = glob.doc.body; + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(img); + img.onload = img.onerror = null; + body.removeChild(img); + }; + img.onerror = onerror; + body.appendChild(img); + img.src = src; + }; + }()); + + /*\ + * Paper.image + [ method ] + ** + * Places an image on the surface + ** + - src (string) URI of the source image + - x (number) x offset position + - y (number) y offset position + - width (number) width of the image + - height (number) height of the image + = (object) the `image` element + * or + = (object) Snap element object with type `image` + ** + > Usage + | var c = paper.image("apple.png", 10, 10, 80, 80); + \*/ + proto.image = function (src, x, y, width, height) { + var el = this.el("image"); + if (is(src, "object") && "src" in src) { + el.attr(src); + } else if (src != null) { + var set = { + "xlink:href": src, + preserveAspectRatio: "none" + }; + if (x != null && y != null) { + set.x = x; + set.y = y; + } + if (width != null && height != null) { + set.width = width; + set.height = height; + } else { + preload(src, function () { + Snap._.$(el.node, { + width: this.offsetWidth, + height: this.offsetHeight + }); + }); + } + Snap._.$(el.node, set); + } + return el; + }; + /*\ + * Paper.ellipse + [ method ] + ** + * Draws an ellipse + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - rx (number) horizontal radius + - ry (number) vertical radius + = (object) the `ellipse` element + ** + > Usage + | var c = paper.ellipse(50, 50, 40, 20); + \*/ + proto.ellipse = function (cx, cy, rx, ry) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr ={ + cx: cx, + cy: cy, + rx: rx, + ry: ry + }; + } + return this.el("ellipse", attr); + }; + // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier. + /*\ + * Paper.path + [ method ] + ** + * Creates a `<path>` element using the given string as the path's definition + - pathString (string) #optional path string in SVG format + * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example: + | "M10,20L30,40" + * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates. + * + # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p> + # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> + # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> + # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> + # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> + # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> + # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> + # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> + # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> + # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> + # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> + # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> + # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> + * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier. + * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point. + > Usage + | var c = paper.path("M10 10L90 90"); + | // draw a diagonal line: + | // move to 10,10, line to 90,90 + \*/ + proto.path = function (d) { + var attr; + if (is(d, "object") && !is(d, "array")) { + attr = d; + } else if (d) { + attr = {d: d}; + } + return this.el("path", attr); + }; + /*\ + * Paper.g + [ method ] + ** + * Creates a group element + ** + - varargs (…) #optional elements to nest within the group + = (object) the `g` element + ** + > Usage + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(c2, c1); // note that the order of elements is different + * or + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(); + | g.add(c2, c1); + \*/ + /*\ + * Paper.group + [ method ] + ** + * See @Paper.g + \*/ + proto.group = proto.g = function (first) { + var attr, + el = this.el("g"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.svg + [ method ] + ** + * Creates a nested SVG element. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `svg` element + ** + \*/ + proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) { + var attrs = {}; + if (is(x, "object") && y == null) { + attrs = x; + } else { + if (x != null) { + attrs.x = x; + } + if (y != null) { + attrs.y = y; + } + if (width != null) { + attrs.width = width; + } + if (height != null) { + attrs.height = height; + } + if (vbx != null && vby != null && vbw != null && vbh != null) { + attrs.viewBox = [vbx, vby, vbw, vbh]; + } + } + return this.el("svg", attrs); + }; + /*\ + * Paper.mask + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a mask. + ** + = (object) the `mask` element + ** + \*/ + proto.mask = function (first) { + var attr, + el = this.el("mask"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.ptrn + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a pattern. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `pattern` element + ** + \*/ + proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) { + if (is(x, "object")) { + var attr = x; + } else { + attr = {patternUnits: "userSpaceOnUse"}; + if (x) { + attr.x = x; + } + if (y) { + attr.y = y; + } + if (width != null) { + attr.width = width; + } + if (height != null) { + attr.height = height; + } + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } else { + attr.viewBox = [x || 0, y || 0, width || 0, height || 0]; + } + } + return this.el("pattern", attr); + }; + /*\ + * Paper.use + [ method ] + ** + * Creates a <use> element. + - id (string) @optional id of element to link + * or + - id (Element) @optional element to link + ** + = (object) the `use` element + ** + \*/ + proto.use = function (id) { + if (id != null) { + if (id instanceof Element) { + if (!id.attr("id")) { + id.attr({id: Snap._.id(id)}); + } + id = id.attr("id"); + } + if (String(id).charAt() == "#") { + id = id.substring(1); + } + return this.el("use", {"xlink:href": "#" + id}); + } else { + return Element.prototype.use.call(this); + } + }; + /*\ + * Paper.symbol + [ method ] + ** + * Creates a <symbol> element. + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + = (object) the `symbol` element + ** + \*/ + proto.symbol = function (vx, vy, vw, vh) { + var attr = {}; + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } + + return this.el("symbol", attr); + }; + /*\ + * Paper.text + [ method ] + ** + * Draws a text string + ** + - x (number) x coordinate position + - y (number) y coordinate position + - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements + = (object) the `text` element + ** + > Usage + | var t1 = paper.text(50, 50, "Snap"); + | var t2 = paper.text(50, 50, ["S","n","a","p"]); + | // Text path usage + | t1.attr({textpath: "M10,10L100,100"}); + | // or + | var pth = paper.path("M10,10L100,100"); + | t1.attr({textpath: pth}); + \*/ + proto.text = function (x, y, text) { + var attr = {}; + if (is(x, "object")) { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + text: text || "" + }; + } + return this.el("text", attr); + }; + /*\ + * Paper.line + [ method ] + ** + * Draws a line + ** + - x1 (number) x coordinate position of the start + - y1 (number) y coordinate position of the start + - x2 (number) x coordinate position of the end + - y2 (number) y coordinate position of the end + = (object) the `line` element + ** + > Usage + | var t1 = paper.line(50, 50, 100, 100); + \*/ + proto.line = function (x1, y1, x2, y2) { + var attr = {}; + if (is(x1, "object")) { + attr = x1; + } else if (x1 != null) { + attr = { + x1: x1, + x2: x2, + y1: y1, + y2: y2 + }; + } + return this.el("line", attr); + }; + /*\ + * Paper.polyline + [ method ] + ** + * Draws a polyline + ** + - points (array) array of points + * or + - varargs (…) points + = (object) the `polyline` element + ** + > Usage + | var p1 = paper.polyline([10, 10, 100, 100]); + | var p2 = paper.polyline(10, 10, 100, 100); + \*/ + proto.polyline = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polyline", attr); + }; + /*\ + * Paper.polygon + [ method ] + ** + * Draws a polygon. See @Paper.polyline + \*/ + proto.polygon = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polygon", attr); + }; + // gradients + (function () { + var $ = Snap._.$; + // gradients' helpers + function Gstops() { + return this.selectAll("stop"); + } + function GaddStop(color, offset) { + var stop = $("stop"), + attr = { + offset: +offset + "%" + }; + color = Snap.color(color); + attr["stop-color"] = color.hex; + if (color.opacity < 1) { + attr["stop-opacity"] = color.opacity; + } + $(stop, attr); + this.node.appendChild(stop); + return this; + } + function GgetBBox() { + if (this.type == "linearGradient") { + var x1 = $(this.node, "x1") || 0, + x2 = $(this.node, "x2") || 1, + y1 = $(this.node, "y1") || 0, + y2 = $(this.node, "y2") || 0; + return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1)); + } else { + var cx = this.node.cx || .5, + cy = this.node.cy || .5, + r = this.node.r || 0; + return Snap._.box(cx - r, cy - r, r * 2, r * 2); + } + } + function gradient(defs, str) { + var grad = eve("snap.util.grad.parse", null, str).firstDefined(), + el; + if (!grad) { + return null; + } + grad.params.unshift(defs); + if (grad.type.toLowerCase() == "l") { + el = gradientLinear.apply(0, grad.params); + } else { + el = gradientRadial.apply(0, grad.params); + } + if (grad.type != grad.type.toLowerCase()) { + $(el.node, { + gradientUnits: "userSpaceOnUse" + }); + } + var stops = grad.stops, + len = stops.length, + start = 0, + j = 0; + function seed(i, end) { + var step = (end - start) / (i - j); + for (var k = j; k < i; k++) { + stops[k].offset = +(+start + step * (k - j)).toFixed(2); + } + j = i; + start = end; + } + len--; + for (var i = 0; i < len; i++) if ("offset" in stops[i]) { + seed(i, stops[i].offset); + } + stops[len].offset = stops[len].offset || 100; + seed(len, stops[len].offset); + for (i = 0; i <= len; i++) { + var stop = stops[i]; + el.addStop(stop.color, stop.offset); + } + return el; + } + function gradientLinear(defs, x1, y1, x2, y2) { + var el = Snap._.make("linearGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (x1 != null) { + $(el.node, { + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }); + } + return el; + } + function gradientRadial(defs, cx, cy, r, fx, fy) { + var el = Snap._.make("radialGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (cx != null) { + $(el.node, { + cx: cx, + cy: cy, + r: r + }); + } + if (fx != null && fy != null) { + $(el.node, { + fx: fx, + fy: fy + }); + } + return el; + } + /*\ + * Paper.gradient + [ method ] + ** + * Creates a gradient element + ** + - gradient (string) gradient descriptor + > Gradient Descriptor + * The gradient descriptor is an expression formatted as + * follows: `<type>(<coords>)<colors>`. The `<type>` can be + * either linear or radial. The uppercase `L` or `R` letters + * indicate absolute coordinates offset from the SVG surface. + * Lowercase `l` or `r` letters indicate coordinates + * calculated relative to the element to which the gradient is + * applied. Coordinates specify a linear gradient vector as + * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`, + * `r` and optional `fx`, `fy` specifying a focal point away + * from the center of the circle. Specify `<colors>` as a list + * of dash-separated CSS color values. Each color may be + * followed by a custom offset value, separated with a colon + * character. + > Examples + * Linear gradient, relative from top-left corner to bottom-right + * corner, from black through red to white: + | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff"); + * Linear gradient, absolute from (0, 0) to (100, 100), from black + * through red at 25% to white: + | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff"); + * Radial gradient, relative from the center of the element with radius + * half the width, from black to white: + | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff"); + * To apply the gradient: + | paper.circle(50, 50, 40).attr({ + | fill: g + | }); + = (object) the `gradient` element + \*/ + proto.gradient = function (str) { + return gradient(this.defs, str); + }; + proto.gradientLinear = function (x1, y1, x2, y2) { + return gradientLinear(this.defs, x1, y1, x2, y2); + }; + proto.gradientRadial = function (cx, cy, r, fx, fy) { + return gradientRadial(this.defs, cx, cy, r, fx, fy); + }; + /*\ + * Paper.toString + [ method ] + ** + * Returns SVG code for the @Paper + = (string) SVG code for the @Paper + \*/ + proto.toString = function () { + var doc = this.node.ownerDocument, + f = doc.createDocumentFragment(), + d = doc.createElement("div"), + svg = this.node.cloneNode(true), + res; + f.appendChild(d); + d.appendChild(svg); + Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"}); + res = d.innerHTML; + f.removeChild(f.firstChild); + return res; + }; + /*\ + * Paper.toDataURL + [ method ] + ** + * Returns SVG code for the @Paper as Data URI string. + = (string) Data URI string + \*/ + proto.toDataURL = function () { + if (window && window.btoa) { + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this))); + } + }; + /*\ + * Paper.clear + [ method ] + ** + * Removes all child nodes of the paper, except <defs>. + \*/ + proto.clear = function () { + var node = this.node.firstChild, + next; + while (node) { + next = node.nextSibling; + if (node.tagName != "defs") { + node.parentNode.removeChild(node); + } else { + proto.clear.call({node: node}); + } + node = next; + } + }; + }()); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + is = Snap.is, + clone = Snap._.clone, + has = "hasOwnProperty", + p2s = /,?([a-z]),?/gi, + toFloat = parseFloat, + math = Math, + PI = math.PI, + mmin = math.min, + mmax = math.max, + pow = math.pow, + abs = math.abs; + function paths(ps) { + var p = paths.ps = paths.ps || {}; + if (p[ps]) { + p[ps].sleep = 100; + } else { + p[ps] = { + sleep: 100 + }; + } + setTimeout(function () { + for (var key in p) if (p[has](key) && key != ps) { + p[key].sleep--; + !p[key].sleep && delete p[key]; + } + }); + return p[ps]; + } + function box(x, y, width, height) { + if (x == null) { + x = y = width = height = 0; + } + if (y == null) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + return { + x: x, + y: y, + width: width, + w: width, + height: height, + h: height, + x2: x + width, + y2: y + height, + cx: x + width / 2, + cy: y + height / 2, + r1: math.min(width, height) / 2, + r2: math.max(width, height) / 2, + r0: math.sqrt(width * width + height * height) / 2, + path: rectPath(x, y, width, height), + vb: [x, y, width, height].join(" ") + }; + } + function toString() { + return this.join(",").replace(p2s, "$1"); + } + function pathClone(pathArray) { + var res = clone(pathArray); + res.toString = toString; + return res; + } + function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + if (length == null) { + return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + } else { + return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, + getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); + } + } + function getLengthFactory(istotal, subpath) { + function O(val) { + return +(+val).toFixed(3); + } + return Snap._.cacher(function (path, length, onlystart) { + if (path instanceof Element) { + path = path.attr("d"); + } + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += [ + "C" + O(point.start.x), + O(point.start.y), + O(point.m.x), + O(point.m.y), + O(point.x), + O(point.y) + ]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = [ + "M" + O(point.x), + O(point.y) + "C" + O(point.n.x), + O(point.n.y), + O(point.end.x), + O(point.end.y), + O(p[5]), + O(p[6]) + ].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return point; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + return point; + }, null, Snap._.clone); + } + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + // (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + } + function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + if (!Snap.is(p1x, "array")) { + p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; + } + var bbox = curveDim.apply(null, p1x); + return box( + bbox.min.x, + bbox.min.y, + bbox.max.x - bbox.min.x, + bbox.max.y - bbox.min.y + ); + } + function isPointInsideBBox(bbox, x, y) { + return x >= bbox.x && + x <= bbox.x + bbox.width && + y >= bbox.y && + y <= bbox.y + bbox.height; + } + function isBBoxIntersect(bbox1, bbox2) { + bbox1 = box(bbox1); + bbox2 = box(bbox2); + return isPointInsideBBox(bbox2, bbox1.x, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2) + || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x + || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) + && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y + || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); + } + function base3(t, p1, p2, p3, p4) { + var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, + t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; + return t * t2 - 3 * p1 + 3 * p2; + } + function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { + if (z == null) { + z = 1; + } + z = z > 1 ? 1 : z < 0 ? 0 : z; + var z2 = z / 2, + n = 12, + Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816], + Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], + sum = 0; + for (var i = 0; i < n; i++) { + var ct = z2 * Tvalues[i] + z2, + xbase = base3(ct, x1, x2, x3, x4), + ybase = base3(ct, y1, y2, y3, y4), + comb = xbase * xbase + ybase * ybase; + sum += Cvalues[i] * math.sqrt(comb); + } + return z2 * sum; + } + function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { + if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { + return; + } + var t = 1, + step = t / 2, + t2 = t - step, + l, + e = .01; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + while (abs(l - ll) > e) { + step /= 2; + t2 += (l < ll ? 1 : -1) * step; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + } + return t2; + } + function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { + if ( + mmax(x1, x2) < mmin(x3, x4) || + mmin(x1, x2) > mmax(x3, x4) || + mmax(y1, y2) < mmin(y3, y4) || + mmin(y1, y2) > mmax(y3, y4) + ) { + return; + } + var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), + ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), + denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + + if (!denominator) { + return; + } + var px = nx / denominator, + py = ny / denominator, + px2 = +px.toFixed(2), + py2 = +py.toFixed(2); + if ( + px2 < +mmin(x1, x2).toFixed(2) || + px2 > +mmax(x1, x2).toFixed(2) || + px2 < +mmin(x3, x4).toFixed(2) || + px2 > +mmax(x3, x4).toFixed(2) || + py2 < +mmin(y1, y2).toFixed(2) || + py2 > +mmax(y1, y2).toFixed(2) || + py2 < +mmin(y3, y4).toFixed(2) || + py2 > +mmax(y3, y4).toFixed(2) + ) { + return; + } + return {x: px, y: py}; + } + function inter(bez1, bez2) { + return interHelper(bez1, bez2); + } + function interCount(bez1, bez2) { + return interHelper(bez1, bez2, 1); + } + function interHelper(bez1, bez2, justCount) { + var bbox1 = bezierBBox(bez1), + bbox2 = bezierBBox(bez2); + if (!isBBoxIntersect(bbox1, bbox2)) { + return justCount ? 0 : []; + } + var l1 = bezlen.apply(0, bez1), + l2 = bezlen.apply(0, bez2), + n1 = ~~(l1 / 8), + n2 = ~~(l2 / 8), + dots1 = [], + dots2 = [], + xy = {}, + res = justCount ? 0 : []; + for (var i = 0; i < n1 + 1; i++) { + var p = findDotsAtSegment.apply(0, bez1.concat(i / n1)); + dots1.push({x: p.x, y: p.y, t: i / n1}); + } + for (i = 0; i < n2 + 1; i++) { + p = findDotsAtSegment.apply(0, bez2.concat(i / n2)); + dots2.push({x: p.x, y: p.y, t: i / n2}); + } + for (i = 0; i < n1; i++) { + for (var j = 0; j < n2; j++) { + var di = dots1[i], + di1 = dots1[i + 1], + dj = dots2[j], + dj1 = dots2[j + 1], + ci = abs(di1.x - di.x) < .001 ? "y" : "x", + cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", + is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); + if (is) { + if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { + continue; + } + xy[is.x.toFixed(4)] = is.y.toFixed(4); + var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), + t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); + if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) { + if (justCount) { + res++; + } else { + res.push({ + x: is.x, + y: is.y, + t1: t1, + t2: t2 + }); + } + } + } + } + } + return res; + } + function pathIntersection(path1, path2) { + return interPathHelper(path1, path2); + } + function pathIntersectionNumber(path1, path2) { + return interPathHelper(path1, path2, 1); + } + function interPathHelper(path1, path2, justCount) { + path1 = path2curve(path1); + path2 = path2curve(path2); + var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, + res = justCount ? 0 : []; + for (var i = 0, ii = path1.length; i < ii; i++) { + var pi = path1[i]; + if (pi[0] == "M") { + x1 = x1m = pi[1]; + y1 = y1m = pi[2]; + } else { + if (pi[0] == "C") { + bez1 = [x1, y1].concat(pi.slice(1)); + x1 = bez1[6]; + y1 = bez1[7]; + } else { + bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; + x1 = x1m; + y1 = y1m; + } + for (var j = 0, jj = path2.length; j < jj; j++) { + var pj = path2[j]; + if (pj[0] == "M") { + x2 = x2m = pj[1]; + y2 = y2m = pj[2]; + } else { + if (pj[0] == "C") { + bez2 = [x2, y2].concat(pj.slice(1)); + x2 = bez2[6]; + y2 = bez2[7]; + } else { + bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; + x2 = x2m; + y2 = y2m; + } + var intr = interHelper(bez1, bez2, justCount); + if (justCount) { + res += intr; + } else { + for (var k = 0, kk = intr.length; k < kk; k++) { + intr[k].segment1 = i; + intr[k].segment2 = j; + intr[k].bez1 = bez1; + intr[k].bez2 = bez2; + } + res = res.concat(intr); + } + } + } + } + } + return res; + } + function isPointInsidePath(path, x, y) { + var bbox = pathBBox(path); + return isPointInsideBBox(bbox, x, y) && + interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; + } + function pathBBox(path) { + var pth = paths(path); + if (pth.bbox) { + return clone(pth.bbox); + } + if (!path) { + return box(); + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X.concat(dim.min.x, dim.max.x); + Y = Y.concat(dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin.apply(0, X), + ymin = mmin.apply(0, Y), + xmax = mmax.apply(0, X), + ymax = mmax.apply(0, Y), + bb = box(xmin, ymin, xmax - xmin, ymax - ymin); + pth.bbox = clone(bb); + return bb; + } + function rectPath(x, y, w, h, r) { + if (r) { + return [ + ["M", +x + (+r), y], + ["l", w - r * 2, 0], + ["a", r, r, 0, 0, 1, r, r], + ["l", 0, h - r * 2], + ["a", r, r, 0, 0, 1, -r, r], + ["l", r * 2 - w, 0], + ["a", r, r, 0, 0, 1, -r, -r], + ["l", 0, r * 2 - h], + ["a", r, r, 0, 0, 1, r, -r], + ["z"] + ]; + } + var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + res.toString = toString; + return res; + } + function ellipsePath(x, y, rx, ry, a) { + if (a == null && ry == null) { + ry = rx; + } + x = +x; + y = +y; + rx = +rx; + ry = +ry; + if (a != null) { + var rad = Math.PI / 180, + x1 = x + rx * Math.cos(-ry * rad), + x2 = x + rx * Math.cos(-a * rad), + y1 = y + rx * Math.sin(-ry * rad), + y2 = y + rx * Math.sin(-a * rad), + res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]]; + } else { + res = [ + ["M", x, y], + ["m", 0, -ry], + ["a", rx, ry, 0, 1, 1, 0, 2 * ry], + ["a", rx, ry, 0, 1, 1, 0, -2 * ry], + ["z"] + ]; + } + res.toString = toString; + return res; + } + var unit2px = Snap._unit2px, + getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx, attr.cy, attr.r); + }, + ellipse: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry); + }, + rect: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry); + }, + image: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height); + }, + line: function (el) { + return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")]; + }, + polyline: function (el) { + return "M" + el.attr("points"); + }, + polygon: function (el) { + return "M" + el.attr("points") + "z"; + }, + deflt: function (el) { + var bbox = el.node.getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }; + function pathToRelative(pathArray) { + var pth = paths(pathArray), + lowerCase = String.prototype.toLowerCase; + if (pth.rel) { + return pathClone(pth.rel); + } + if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) { + pathArray = Snap.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = toString; + pth.rel = pathClone(res); + return res; + } + function pathToAbsolute(pathArray) { + var pth = paths(pathArray); + if (pth.abs) { + return pathClone(pth.abs); + } + if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption + pathArray = Snap.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0, + pa0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + var crz = pathArray.length == 3 && + pathArray[0][0] == "M" && + pathArray[1][0].toUpperCase() == "R" && + pathArray[2][0].toUpperCase() == "Z"; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + pa0 = pa[0]; + if (pa0 != pa0.toUpperCase()) { + r[0] = pa0.toUpperCase(); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +pa[6] + x; + r[7] = +pa[7] + y; + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y].concat(pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + break; + case "O": + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + break; + case "U": + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa0 == "R") { + dots = [x, y].concat(pa.slice(1)); + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + r = ["R"].concat(pa.slice(-2)); + } else if (pa0 == "O") { + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + } else if (pa0 == "U") { + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + pa0 = pa0.toUpperCase(); + if (pa0 != "O") { + switch (r[0]) { + case "Z": + x = +mx; + y = +my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + } + res.toString = toString; + pth.abs = pathClone(res); + return res; + } + function l2c(x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + } + function q2c(x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + } + function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = Snap._.cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4].concat(res); + } else { + res = [m2, m3, m4].concat(res).join().split(","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + } + function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + } + + // Returns bounding box of cubic bezier curve. + // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + // Original version: NISHIO Hirokazu + // Modifications: https://github.com/timo22345 + function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) { + var tvalues = [], + bounds = [[], []], + a, b, c, t, t1, t2, b2ac, sqrtb2ac; + for (var i = 0; i < 2; ++i) { + if (i == 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + if (abs(a) < 1e-12) { + if (abs(b) < 1e-12) { + continue; + } + t = -c / b; + if (0 < t && t < 1) { + tvalues.push(t); + } + continue; + } + b2ac = b * b - 4 * c * a; + sqrtb2ac = math.sqrt(b2ac); + if (b2ac < 0) { + continue; + } + t1 = (-b + sqrtb2ac) / (2 * a); + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + t2 = (-b - sqrtb2ac) / (2 * a); + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + var x, y, j = tvalues.length, + jlen = j, + mt; + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); + bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + + + return { + min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])}, + max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])} + }; + } + + function path2curve(path, path2) { + var pth = !path2 && paths(path); + if (!path2 && pth.curve) { + return pathClone(pth.curve); + } + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d, pcom) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); + break; + case "S": + if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. + nx = d.x * 2 - d.bx; // And reflect the previous + ny = d.y * 2 - d.by; // command's control point relative to the current point. + } + else { // or some else or nothing + nx = d.x; + ny = d.y; + } + path = ["C", nx, ny].concat(path.slice(1)); + break; + case "T": + if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. + d.qx = d.x * 2 - d.qx; // And make a reflection similar + d.qy = d.y * 2 - d.qy; // to case "S". + } + else { // or something else or nothing + d.qx = d.x; + d.qy = d.y; + } + path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"].concat(l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"].concat(l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"].concat(l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved + p2 && (pcoms2[i] = "A"); // the same as above + pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + pcoms1 = [], // path commands of original path p + pcoms2 = [], // path commands of original path p2 + pfirst = "", // temporary holder for original path command + pcom = ""; // holder for previous path command of original path + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] && (pfirst = p[i][0]); // save current path command + + if (pfirst != "C") // C is not saved yet, because it may be result of conversion + { + pcoms1[i] = pfirst; // Save current path command + i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom + } + p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath + + if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command + // which may produce multiple C:s + // so we have to make sure that C is also C in original path + + fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 + + if (p2) { // the same procedures is done to p2 + p2[i] && (pfirst = p2[i][0]); + if (pfirst != "C") { + pcoms2[i] = pfirst; + i && (pcom = pcoms2[i - 1]); + } + p2[i] = processPath(p2[i], attrs2, pcom); + + if (pcoms2[i] != "A" && pfirst == "C") { + pcoms2[i] = "C"; + } + + fixArc(p2, i); + } + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + if (!p2) { + pth.curve = pathClone(p); + } + return p2 ? [p, p2] : p; + } + function mapPath(path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + } + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 == i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 == i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 == i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + // export + Snap.path = paths; + + /*\ + * Snap.path.getTotalLength + [ method ] + ** + * Returns the length of the given path in pixels + ** + - path (string) SVG path string + ** + = (number) length + \*/ + Snap.path.getTotalLength = getTotalLength; + /*\ + * Snap.path.getPointAtLength + [ method ] + ** + * Returns the coordinates of the point located at the given length along the given path + ** + - path (string) SVG path string + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + Snap.path.getPointAtLength = getPointAtLength; + /*\ + * Snap.path.getSubpath + [ method ] + ** + * Returns the subpath of a given path between given start and end lengths + ** + - path (string) SVG path string + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + Snap.path.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + /*\ + * Element.getTotalLength + [ method ] + ** + * Returns the length of the path in pixels (only works for `path` elements) + = (number) length + \*/ + elproto.getTotalLength = function () { + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + }; + // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length? + /*\ + * Element.getPointAtLength + [ method ] + ** + * Returns coordinates of the point located at the given length on the given path (only works for `path` elements) + ** + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + elproto.getPointAtLength = function (length) { + return getPointAtLength(this.attr("d"), length); + }; + // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear. + /*\ + * Element.getSubpath + [ method ] + ** + * Returns subpath of a given element from given start and end lengths (only works for `path` elements) + ** + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + elproto.getSubpath = function (from, to) { + return Snap.path.getSubpath(this.attr("d"), from, to); + }; + Snap._.box = box; + /*\ + * Snap.path.findDotsAtSegment + [ method ] + ** + * Utility method + ** + * Finds dot coordinates on the given cubic beziér curve at the given t + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + - t (number) position on the curve (0..1) + = (object) point information in format: + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o m: { + o x: (number) x coordinate of the left anchor, + o y: (number) y coordinate of the left anchor + o }, + o n: { + o x: (number) x coordinate of the right anchor, + o y: (number) y coordinate of the right anchor + o }, + o start: { + o x: (number) x coordinate of the start of the curve, + o y: (number) y coordinate of the start of the curve + o }, + o end: { + o x: (number) x coordinate of the end of the curve, + o y: (number) y coordinate of the end of the curve + o }, + o alpha: (number) angle of the curve derivative at the point + o } + \*/ + Snap.path.findDotsAtSegment = findDotsAtSegment; + /*\ + * Snap.path.bezierBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given cubic beziér curve + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + * or + - bez (array) array of six points for beziér curve + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.bezierBBox = bezierBBox; + /*\ + * Snap.path.isPointInsideBBox + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside bounding box + - bbox (string) bounding box + - x (string) x coordinate of the point + - y (string) y coordinate of the point + = (boolean) `true` if point is inside + \*/ + Snap.path.isPointInsideBBox = isPointInsideBBox; + Snap.closest = function (x, y, X, Y) { + var r = 100, + b = box(x - r / 2, y - r / 2, r, r), + inside = [], + getter = X[0].hasOwnProperty("x") ? function (i) { + return { + x: X[i].x, + y: X[i].y + }; + } : function (i) { + return { + x: X[i], + y: Y[i] + }; + }, + found = 0; + while (r <= 1e6 && !found) { + for (var i = 0, ii = X.length; i < ii; i++) { + var xy = getter(i); + if (isPointInsideBBox(b, xy.x, xy.y)) { + found++; + inside.push(xy); + break; + } + } + if (!found) { + r *= 2; + b = box(x - r / 2, y - r / 2, r, r) + } + } + if (r == 1e6) { + return; + } + var len = Infinity, + res; + for (i = 0, ii = inside.length; i < ii; i++) { + var l = Snap.len(x, y, inside[i].x, inside[i].y); + if (len > l) { + len = l; + inside[i].len = l; + res = inside[i]; + } + } + return res; + }; + /*\ + * Snap.path.isBBoxIntersect + [ method ] + ** + * Utility method + ** + * Returns `true` if two bounding boxes intersect + - bbox1 (string) first bounding box + - bbox2 (string) second bounding box + = (boolean) `true` if bounding boxes intersect + \*/ + Snap.path.isBBoxIntersect = isBBoxIntersect; + /*\ + * Snap.path.intersection + [ method ] + ** + * Utility method + ** + * Finds intersections of two paths + - path1 (string) path string + - path2 (string) path string + = (array) dots of intersection + o [ + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o t1: (number) t value for segment of path1, + o t2: (number) t value for segment of path2, + o segment1: (number) order number for segment of path1, + o segment2: (number) order number for segment of path2, + o bez1: (array) eight coordinates representing beziér curve for the segment of path1, + o bez2: (array) eight coordinates representing beziér curve for the segment of path2 + o } + o ] + \*/ + Snap.path.intersection = pathIntersection; + Snap.path.intersectionNumber = pathIntersectionNumber; + /*\ + * Snap.path.isPointInside + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside a given closed path. + * + * Note: fill mode doesn’t affect the result of this method. + - path (string) path string + - x (number) x of the point + - y (number) y of the point + = (boolean) `true` if point is inside the path + \*/ + Snap.path.isPointInside = isPointInsidePath; + /*\ + * Snap.path.getBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given path + - path (string) path string + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.getBBox = pathBBox; + Snap.path.get = getPath; + /*\ + * Snap.path.toRelative + [ method ] + ** + * Utility method + ** + * Converts path coordinates into relative values + - path (string) path string + = (array) path string + \*/ + Snap.path.toRelative = pathToRelative; + /*\ + * Snap.path.toAbsolute + [ method ] + ** + * Utility method + ** + * Converts path coordinates into absolute values + - path (string) path string + = (array) path string + \*/ + Snap.path.toAbsolute = pathToAbsolute; + /*\ + * Snap.path.toCubic + [ method ] + ** + * Utility method + ** + * Converts path to a new path where all segments are cubic beziér curves + - pathString (string|array) path string or array of segments + = (array) array of segments + \*/ + Snap.path.toCubic = path2curve; + /*\ + * Snap.path.map + [ method ] + ** + * Transform the path string with the given matrix + - path (string) path string + - matrix (object) see @Matrix + = (string) transformed path string + \*/ + Snap.path.map = mapPath; + Snap.path.toString = toString; + Snap.path.clone = pathClone; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var mmax = Math.max, + mmin = Math.min; + + // Set + var Set = function (items) { + this.items = []; + this.bindings = {}; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i]) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + /*\ + * Set.push + [ method ] + ** + * Adds each argument to the current set + = (object) original element + \*/ + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + /*\ + * Set.pop + [ method ] + ** + * Removes last element and returns it + = (object) element + \*/ + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + /*\ + * Set.forEach + [ method ] + ** + * Executes given function for each element in the set + * + * If the function returns `false`, the loop stops running. + ** + - callback (function) function to run + - thisArg (object) context object for the callback + = (object) Set object + \*/ + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + /*\ + * Set.animate + [ method ] + ** + * Animates each element in set in sync. + * + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + * or + - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]` + > Usage + | // animate all elements in set to radius 10 + | set.animate({r: 10}, 500, mina.easein); + | // or + | // animate first element to radius 10, but second to radius 20 and in different time + | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]); + = (Element) the current element + \*/ + setproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Snap._.Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = easing.dur; + attrs = attrs.attr; + } + var args = arguments; + if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) { + var each = true; + } + var begin, + handler = function () { + if (begin) { + this.b = begin; + } else { + begin = this.b; + } + }, + cb = 0, + set = this, + callbacker = callback && function () { + if (++cb == set.length) { + callback.call(this); + } + }; + return this.forEach(function (el, i) { + eve.once("snap.animcreated." + el.id, handler); + if (each) { + args[i] && el.animate.apply(el, args[i]); + } else { + el.animate(attrs, ms, easing, callbacker); + } + }); + }; + setproto.remove = function () { + while (this.length) { + this.pop().remove(); + } + return this; + }; + /*\ + * Set.bind + [ method ] + ** + * Specifies how to handle a specific attribute when applied + * to a set. + * + ** + - attr (string) attribute name + - callback (function) function to run + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + - eattr (string) attribute on the element to bind the attribute to + = (object) Set object + \*/ + setproto.bind = function (attr, a, b) { + var data = {}; + if (typeof a == "function") { + this.bindings[attr] = a; + } else { + var aname = b || attr; + this.bindings[attr] = function (v) { + data[aname] = v; + a.attr(data); + }; + } + return this; + }; + setproto.attr = function (value) { + var unbound = {}; + for (var k in value) { + if (this.bindings[k]) { + this.bindings[k](value[k]); + } else { + unbound[k] = value[k]; + } + } + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(unbound); + } + return this; + }; + /*\ + * Set.clear + [ method ] + ** + * Removes all elements from the set + \*/ + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + /*\ + * Set.splice + [ method ] + ** + * Removes range of elements from the set + ** + - index (number) position of the deletion + - count (number) number of element to remove + - insertion… (object) #optional elements to insert + = (object) set elements that were deleted + \*/ + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + /*\ + * Set.exclude + [ method ] + ** + * Removes given element from the set + ** + - element (object) element to remove + = (boolean) `true` if object was found and removed from the set + \*/ + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + return false; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + x2 = [], + y2 = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + x2.push(box.x + box.width); + y2.push(box.y + box.height); + } + x = mmin.apply(0, x); + y = mmin.apply(0, y); + x2 = mmax.apply(0, x2); + y2 = mmax.apply(0, y2); + return { + x: x, + y: y, + x2: x2, + y2: y2, + width: x2 - x, + height: y2 - y, + cx: x + (x2 - x) / 2, + cy: y + (y2 - y) / 2 + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Snap\u2018s set"; + }; + setproto.type = "set"; + // export + Snap.Set = Set; + Snap.set = function () { + var set = new Set; + if (arguments.length) { + set.push.apply(set, Array.prototype.slice.call(arguments, 0)); + } + return set; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var names = {}, + reUnit = /[a-z]+$/i, + Str = String; + names.stroke = names.fill = "colour"; + function getEmpty(item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + } + function equaliseTransform(t1, t2, getBBox) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = Snap.parseTransformString(t1) || []; + t2 = Snap.parseTransformString(t2) || []; + var maxlength = Math.max(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + t1 = Snap._.transform2matrix(t1, getBBox()); + t2 = Snap._.transform2matrix(t2, getBBox()); + from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]]; + to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]]; + break; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: path2array(from), + to: path2array(to), + f: getPath(from) + }; + } + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + function getViewBox(val) { + return val.join(" "); + } + function getColour(clr) { + return Snap.rgb(clr[0], clr[1], clr[2]); + } + function getPath(path) { + var k = 0, i, ii, j, jj, out, a, b = []; + for (i = 0, ii = path.length; i < ii; i++) { + out = "["; + a = ['"' + path[i][0] + '"']; + for (j = 1, jj = path[i].length; j < jj; j++) { + a[j] = "val[" + (k++) + "]"; + } + out += a + "]"; + b[i] = out; + } + return Function("val", "return Snap.path.toString.call([" + b + "])"); + } + function path2array(path) { + var out = []; + for (var i = 0, ii = path.length; i < ii; i++) { + for (var j = 1, jj = path[i].length; j < jj; j++) { + out.push(path[i][j]); + } + } + return out; + } + function isNumeric(obj) { + return isFinite(parseFloat(obj)); + } + function arrayEqual(arr1, arr2) { + if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) { + return false; + } + return arr1.toString() == arr2.toString(); + } + Element.prototype.equal = function (name, b) { + return eve("snap.util.equal", this, name, b).firstDefined(); + }; + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this; + if (isNumeric(a) && isNumeric(b)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getNumber + }; + } + if (names[name] == "colour") { + A = Snap.color(a); + B = Snap.color(b); + return { + from: [A.r, A.g, A.b, A.opacity], + to: [B.r, B.g, B.b, B.opacity], + f: getColour + }; + } + if (name == "viewBox") { + A = this.attr(name).vb.split(" ").map(Number); + B = b.split(" ").map(Number); + return { + from: A, + to: B, + f: getViewBox + }; + } + if (name == "transform" || name == "gradientTransform" || name == "patternTransform") { + if (b instanceof Snap.Matrix) { + b = b.toTransformString(); + } + if (!Snap._.rgTransform.test(b)) { + b = Snap._.svgTransform2string(b); + } + return equaliseTransform(a, b, function () { + return el.getBBox(1); + }); + } + if (name == "d" || name == "path") { + A = Snap.path.toCubic(a, b); + return { + from: path2array(A[0]), + to: path2array(A[1]), + f: getPath(A[0]) + }; + } + if (name == "points") { + A = Str(a).split(Snap._.separator); + B = Str(b).split(Snap._.separator); + return { + from: A, + to: B, + f: function (val) { return val; } + }; + } + var aUnit = a.match(reUnit), + bUnit = Str(b).match(reUnit); + if (aUnit && arrayEqual(aUnit, bUnit)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getUnit(aUnit) + }; + } else { + return { + from: this.asPX(name), + to: this.asPX(name, b), + f: getNumber + }; + } + }); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + has = "hasOwnProperty", + supportsTouch = "createTouch" in glob.doc, + events = [ + "click", "dblclick", "mousedown", "mousemove", "mouseout", + "mouseover", "mouseup", "touchstart", "touchmove", "touchend", + "touchcancel" + ], + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + getScroll = function (xy, el) { + var name = xy == "y" ? "scrollTop" : "scrollLeft", + doc = el && el.node ? el.node.ownerDocument : glob.doc; + return doc[name in doc.documentElement ? "documentElement" : "body"][name]; + }, + preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = getScroll("y", element), + scrollX = getScroll("x", element); + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + var x = e.clientX + scrollX, + y = e.clientY + scrollY; + return fn.call(element, e, x, y); + }; + + if (type !== realName) { + obj.addEventListener(type, f, false); + } + + obj.addEventListener(realName, f, false); + + return function () { + if (type !== realName) { + obj.removeEventListener(type, f, false); + } + + obj.removeEventListener(realName, f, false); + return true; + }; + }, + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = getScroll("y"), + scrollX = getScroll("x"), + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches && e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + // glob.win.opera && parent.removeChild(node); + // node.style.display = "none"; + // o = dragi.el.paper.getElementByPoint(x, y); + // node.style.display = display; + // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + Snap.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + eve.off("snap.drag.*." + dragi.el.id); + } + drag = []; + }; + /*\ + * Element.click + [ method ] + ** + * Adds a click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unclick + [ method ] + ** + * Removes a click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.dblclick + [ method ] + ** + * Adds a double click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.undblclick + [ method ] + ** + * Removes a double click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousedown + [ method ] + ** + * Adds a mousedown event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousedown + [ method ] + ** + * Removes a mousedown event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousemove + [ method ] + ** + * Adds a mousemove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousemove + [ method ] + ** + * Removes a mousemove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseout + [ method ] + ** + * Adds a mouseout event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseout + [ method ] + ** + * Removes a mouseout event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseover + [ method ] + ** + * Adds a mouseover event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseover + [ method ] + ** + * Removes a mouseover event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseup + [ method ] + ** + * Adds a mouseup event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseup + [ method ] + ** + * Removes a mouseup event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchstart + [ method ] + ** + * Adds a touchstart event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchstart + [ method ] + ** + * Removes a touchstart event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchmove + [ method ] + ** + * Adds a touchmove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchmove + [ method ] + ** + * Removes a touchmove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchend + [ method ] + ** + * Adds a touchend event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchend + [ method ] + ** + * Removes a touchend event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchcancel + [ method ] + ** + * Adds a touchcancel event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchcancel + [ method ] + ** + * Removes a touchcancel event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + for (var i = events.length; i--;) { + (function (eventName) { + Snap[eventName] = elproto[eventName] = function (fn, scope) { + if (Snap.is(fn, "function")) { + this.events = this.events || []; + this.events.push({ + name: eventName, + f: fn, + unbind: addEvent(this.node || document, eventName, fn, scope || this) + }); + } else { + for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) { + try { + this.events[i].f.call(this); + } catch (e) {} + } + } + return this; + }; + Snap["un" + eventName] = + elproto["un" + eventName] = function (fn) { + var events = this.events || [], + l = events.length; + while (l--) if (events[l].name == eventName && + (events[l].f == fn || !fn)) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + /*\ + * Element.hover + [ method ] + ** + * Adds hover event handlers to the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + - icontext (object) #optional context for hover in handler + - ocontext (object) #optional context for hover out handler + = (object) @Element + \*/ + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + /*\ + * Element.unhover + [ method ] + ** + * Removes hover event handlers from the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + = (object) @Element + \*/ + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture. + // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from? + // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason. + // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID? + /*\ + * Element.drag + [ method ] + ** + * Adds event handlers for an element's drag gesture + ** + - onmove (function) handler for moving + - onstart (function) handler for drag start + - onend (function) handler for drag end + - mcontext (object) #optional context for moving handler + - scontext (object) #optional context for drag start handler + - econtext (object) #optional context for drag end handler + * Additionaly following `drag` events are triggered: `drag.start.<id>` on start, + * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element + * `drag.over.<id>` fires as well. + * + * Start event and start handler are called in specified context or in context of the element with following parameters: + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * Move event and move handler are called in specified context or in context of the element with following parameters: + o dx (number) shift by x from the start point + o dy (number) shift by y from the start point + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * End event and end handler are called in specified context or in context of the element with following parameters: + o event (object) DOM event object + = (object) @Element + \*/ + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + var el = this; + if (!arguments.length) { + var origTransform; + return el.drag(function (dx, dy) { + this.attr({ + transform: origTransform + (origTransform ? "T" : "t") + [dx, dy] + }); + }, function () { + origTransform = this.transform().local; + }); + } + function start(e, x, y) { + (e.originalEvent || e).preventDefault(); + el._drag.x = x; + el._drag.y = y; + el._drag.id = e.identifier; + !drag.length && Snap.mousemove(dragMove).mouseup(dragUp); + drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("snap.drag.start." + el.id, onstart); + onmove && eve.on("snap.drag.move." + el.id, onmove); + onend && eve.on("snap.drag.end." + el.id, onend); + eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e); + } + function init(e, x, y) { + eve("snap.draginit." + el.id, el, e, x, y); + } + eve.on("snap.draginit." + el.id, start); + el._drag = {}; + draggable.push({el: el, start: start, init: init}); + el.mousedown(init); + return el; + }; + /* + * Element.onDragOver + [ method ] + ** + * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id) + - f (function) handler for event, first argument would be the element you are dragging over + \*/ + // elproto.onDragOver = function (f) { + // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id); + // }; + /*\ + * Element.undrag + [ method ] + ** + * Removes all drag event handlers from the given element + \*/ + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].init); + draggable.splice(i, 1); + eve.unbind("snap.drag.*." + this.id); + eve.unbind("snap.draginit." + this.id); + } + !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp); + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + pproto = Paper.prototype, + rgurl = /^\s*url\((.+)\)/, + Str = String, + $ = Snap._.$; + Snap.filter = {}; + /*\ + * Paper.filter + [ method ] + ** + * Creates a `<filter>` element + ** + - filstr (string) SVG fragment of filter provided as a string + = (object) @Element + * Note: It is recommended to use filters embedded into the page inside an empty SVG element. + > Usage + | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + pproto.filter = function (filstr) { + var paper = this; + if (paper.type != "svg") { + paper = paper.paper; + } + var f = Snap.parse(Str(filstr)), + id = Snap._.id(), + width = paper.node.offsetWidth, + height = paper.node.offsetHeight, + filter = $("filter"); + $(filter, { + id: id, + filterUnits: "userSpaceOnUse" + }); + filter.appendChild(f.node); + paper.defs.appendChild(filter); + return new Element(filter); + }; + + eve.on("snap.util.getattr.filter", function () { + eve.stop(); + var p = $(this.node, "filter"); + if (p) { + var match = Str(p).match(rgurl); + return match && Snap.select(match[1]); + } + }); + eve.on("snap.util.attr.filter", function (value) { + if (value instanceof Element && value.type == "filter") { + eve.stop(); + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + id = value.id; + } + $(this.node, { + filter: Snap.url(id) + }); + } + if (!value || value == "none") { + eve.stop(); + this.node.removeAttribute("filter"); + } + }); + /*\ + * Snap.filter.blur + [ method ] + ** + * Returns an SVG markup string for the blur filter + ** + - x (number) amount of horizontal blur, in pixels + - y (number) #optional amount of vertical blur, in pixels + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.blur(5, 10)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.blur = function (x, y) { + if (x == null) { + x = 2; + } + var def = y == null ? x : [x, y]; + return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', { + def: def + }); + }; + Snap.filter.blur.toString = function () { + return this(); + }; + /*\ + * Snap.filter.shadow + [ method ] + ** + * Returns an SVG markup string for the shadow filter + ** + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - blur (number) #optional amount of blur + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * which makes blur default to `4`. Or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - opacity (number) #optional `0..1` opacity of the shadow + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.shadow(0, 2, 3)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.shadow = function (dx, dy, blur, color, opacity) { + if (typeof blur == "string") { + color = blur; + opacity = color; + blur = 4; + } + if (typeof color != "string") { + opacity = color; + color = "#000"; + } + color = color || "#000"; + if (blur == null) { + blur = 4; + } + if (opacity == null) { + opacity = 1; + } + if (dx == null) { + dx = 0; + dy = 2; + } + if (dy == null) { + dy = dx; + } + color = Snap.color(color); + return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', { + color: color, + dx: dx, + dy: dy, + blur: blur, + opacity: opacity + }); + }; + Snap.filter.shadow.toString = function () { + return this(); + }; + /*\ + * Snap.filter.grayscale + [ method ] + ** + * Returns an SVG markup string for the grayscale filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.grayscale = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', { + a: 0.2126 + 0.7874 * (1 - amount), + b: 0.7152 - 0.7152 * (1 - amount), + c: 0.0722 - 0.0722 * (1 - amount), + d: 0.2126 - 0.2126 * (1 - amount), + e: 0.7152 + 0.2848 * (1 - amount), + f: 0.0722 - 0.0722 * (1 - amount), + g: 0.2126 - 0.2126 * (1 - amount), + h: 0.0722 + 0.9278 * (1 - amount) + }); + }; + Snap.filter.grayscale.toString = function () { + return this(); + }; + /*\ + * Snap.filter.sepia + [ method ] + ** + * Returns an SVG markup string for the sepia filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.sepia = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', { + a: 0.393 + 0.607 * (1 - amount), + b: 0.769 - 0.769 * (1 - amount), + c: 0.189 - 0.189 * (1 - amount), + d: 0.349 - 0.349 * (1 - amount), + e: 0.686 + 0.314 * (1 - amount), + f: 0.168 - 0.168 * (1 - amount), + g: 0.272 - 0.272 * (1 - amount), + h: 0.534 - 0.534 * (1 - amount), + i: 0.131 + 0.869 * (1 - amount) + }); + }; + Snap.filter.sepia.toString = function () { + return this(); + }; + /*\ + * Snap.filter.saturate + [ method ] + ** + * Returns an SVG markup string for the saturate filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.saturate = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', { + amount: 1 - amount + }); + }; + Snap.filter.saturate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.hueRotate + [ method ] + ** + * Returns an SVG markup string for the hue-rotate filter + ** + - angle (number) angle of rotation + = (string) filter representation + \*/ + Snap.filter.hueRotate = function (angle) { + angle = angle || 0; + return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', { + angle: angle + }); + }; + Snap.filter.hueRotate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.invert + [ method ] + ** + * Returns an SVG markup string for the invert filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.invert = function (amount) { + if (amount == null) { + amount = 1; + } +// <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" color-interpolation-filters="sRGB"/> + return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: 1 - amount + }); + }; + Snap.filter.invert.toString = function () { + return this(); + }; + /*\ + * Snap.filter.brightness + [ method ] + ** + * Returns an SVG markup string for the brightness filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.brightness = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', { + amount: amount + }); + }; + Snap.filter.brightness.toString = function () { + return this(); + }; + /*\ + * Snap.filter.contrast + [ method ] + ** + * Returns an SVG markup string for the contrast filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.contrast = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: .5 - amount / 2 + }); + }; + Snap.filter.contrast.toString = function () { + return this(); + }; +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var box = Snap._.box, + is = Snap.is, + firstLetter = /^[^a-z]*([tbmlrc])/i, + toString = function () { + return "T" + this.dx + "," + this.dy; + }; + /*\ + * Element.getAlign + [ method ] + ** + * Returns shift needed to align the element relatively to given element. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string + > Usage + | el.transform(el.getAlign(el2, "top")); + * or + | var dy = el.getAlign(el2, "top").dy; + \*/ + Element.prototype.getAlign = function (el, way) { + if (way == null && is(el, "string")) { + way = el; + el = null; + } + el = el || this.paper; + var bx = el.getBBox ? el.getBBox() : box(el), + bb = this.getBBox(), + out = {}; + way = way && way.match(firstLetter); + way = way ? way[1].toLowerCase() : "c"; + switch (way) { + case "t": + out.dx = 0; + out.dy = bx.y - bb.y; + break; + case "b": + out.dx = 0; + out.dy = bx.y2 - bb.y2; + break; + case "m": + out.dx = 0; + out.dy = bx.cy - bb.cy; + break; + case "l": + out.dx = bx.x - bb.x; + out.dy = 0; + break; + case "r": + out.dx = bx.x2 - bb.x2; + out.dy = 0; + break; + default: + out.dx = bx.cx - bb.cx; + out.dy = 0; + break; + } + out.toString = toString; + return out; + }; + /*\ + * Element.align + [ method ] + ** + * Aligns the element relatively to given one via transformation. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object) this element + > Usage + | el.align(el2, "top"); + * or + | el.align("middle"); + \*/ + Element.prototype.align = function (el, way) { + return this.transform("..." + this.getAlign(el, way)); + }; +}); + +return Snap; +})); diff --git a/web/pgadmin/misc/templates/explain/js/explain.js b/web/pgadmin/misc/templates/explain/js/explain.js new file mode 100644 index 0000000..bedc51e --- /dev/null +++ b/web/pgadmin/misc/templates/explain/js/explain.js @@ -0,0 +1,688 @@ +define ( + 'pgadmin.misc.explain', + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'backbone', 'snap.svg'], + function($, _, S, pgAdmin, Backbone, Snap) { + +pgAdmin = pgAdmin || window.pgAdmin || {}; +var pgExplain = pgAdmin.Explain; + +// Snap.svg plug-in to write multitext as image name +Snap.plugin(function (Snap, Element, Paper, glob) { + Paper.prototype.multitext = function (x, y, txt, max_width, attributes) { + var svg = Snap(), + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + isWordBroken = false, + temp = svg.text(0, 0, abc); + + temp.attr(attributes); + + /* + * Find letter width in pixels and + * index from where the text should be broken + */ + var letter_width = temp.getBBox().width / abc.length, + word_break_index = Math.round((max_width / letter_width)) - 1; + + svg.remove(); + + var words = txt.split(" "), + width_so_far = 0, + lines=[], curr_line = '', + /* + * Function to divide string into multiple lines + * and store them in an array if it size crosses + * the max-width boundary. + */ + splitTextInMultiLine = function(leading, so_far, line) { + var l = line.length, + res = []; + + if (l == 0) + return res; + + if (so_far && (so_far + (l * letter_width) > max_width)) { + res.push(leading); + res = res.concat(splitTextInMultiLine('', 0, line)); + } else if (so_far) { + res.push(leading + ' ' + line); + } else { + if (leading) + res.push(leading); + if (line.length > word_break_index + 1) + res.push(line.slice(0, word_break_index) + '-'); + else + res.push(line); + res = res.concat(splitTextInMultiLine('', 0, line.slice(word_break_index))); + } + + return res; + }; + + for (var i = 0; i < words.length; i++) { + var tmpArr = splitTextInMultiLine( + curr_line, width_so_far, words[i] + ); + + if (curr_line) { + lines = lines.slice(0, lines.length - 2); + } + lines = lines.concat(tmpArr); + curr_line = lines[lines.length - 1]; + width_so_far = (curr_line.length * letter_width); + } + + // Create multiple tspan for each string in array + var t = this.text(x,y,lines).attr(attributes); + t.selectAll("tspan:nth-child(n+2)").attr({ + dy: "1.2em", + x: x + }); + return t; + }; +}); + +if (pgAdmin.Explain) + return pgAdmin.Explain; + +var pgExplain = pgAdmin.Explain = { + // Prefix path where images are stored + prefix: '{{ url_for('misc.static', filename='explain/img') }}/' +}; + +/* + * A map which is used to fetch the image to be drawn and + * text which will appear below it + */ +var imageMapper = { + "Aggregate" : { + "image":"ex_aggregate.png", "image_text":"Aggregate" + }, + 'Append' : { + "image":"ex_append.png","image_text":"Append" + }, + "Bitmap Index Scan" : function(data) { + return { + "image":"ex_bmp_index.png", "image_text":data['Index Name'] + }; + }, + "Bitmap Heap Scan" : function(data) { + return {"image":"ex_bmp_heap.png","image_text":data['Relation Name']}; +}, +"BitmapAnd" : {"image":"ex_bmp_and.png","image_text":"Bitmap AND"}, +"BitmapOr" : {"image":"ex_bmp_or.png","image_text":"Bitmap OR"}, +"CTE Scan" : {"image":"ex_cte_scan.png","image_text":"CTE Scan"}, +"Function Scan" : {"image":"ex_result.png","image_text":"Function Scan"}, +"Foreign Scan" : {"image":"ex_foreign_scan.png","image_text":"Foreign Scan"}, +"Gather" : {"image":"ex_gather_motion.png","image_text":"Gather"}, +"Group" : {"image":"ex_group.png","image_text":"Group"}, +"GroupAggregate": {"image":"ex_aggregate.png","image_text":"Group Aggregate"}, +"Hash" : {"image":"ex_hash.png","image_text":"Hash"}, +"Hash Join": function(data) { + if (!data['Join Type']) return {"image":"ex_join.png","image_text":"Join"}; + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_hash_anti_join.png","image_text":"Hash Anti Join"}; + case 'Semi': return {"image":"ex_hash_semi_join.png","image_text":"Hash Semi Join"}; + default: return {"image":"ex_hash.png","image_text":String("Hash " + data['Join Type'] + " Join" )}; + } +}, +"HashAggregate" : {"image":"ex_aggregate.png","image_text":"Hash Aggregate"}, +"Index Only Scan" : function(data) { + return {"image":"ex_index_only_scan.png","image_text":data['Index Name']}; +}, +"Index Scan" : function(data) { + return {"image":"ex_index_scan.png","image_text":data['Index Name']}; +}, +"Index Scan Backword" : {"image":"ex_index_scan.png","image_text":"Index Backward Scan"}, +"Limit" : {"image":"ex_limit.png","image_text":"Limit"}, +"LockRows" : {"image":"ex_lock_rows.png","image_text":"Lock Rows"}, +"Materialize" : {"image":"ex_materialize.png","image_text":"Materialize"}, +"Merge Append": {"image":"ex_merge_append.png","image_text":"Merge Append"}, +"Merge Join": function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_merge_anti_join.png","image_text":"Merge Anti Join"}; + case 'Semi': return {"image":"ex_merge_semi_join.png","image_text":"Merge Semi Join"}; + default: return {"image":"ex_merge.png","image_text":String("Merge " + data['Join Type'] + " Join" )}; + } +}, +"ModifyTable" : function(data) { + switch (data['Operaton']) { + case "insert": return { "image":"ex_insert.png", + "image_text":"Insert" + }; + case "update": return {"image":"ex_update.png","image_text":"Update"}; + case "Delete": return {"image":"ex_delete.png","image_text":"Delete"}; + } +}, +'Nested Loop' : function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_nested_loop_anti_join.png","image_text":"Nested Loop Anti Join"}; + case 'Semi': return {"image":"ex_nested_loop_semi_join.png","image_text":"Nested Loop Semi Join"}; + default: return {"image":"ex_nested.png","image_text":"Nested Loop " + data['Join Type'] + " Join"}; + } +}, +"Recursive Union" : {"image":"ex_recursive_union.png","image_text":"Recursive Union"}, +"Result" : {"image":"ex_result.png","image_text":"Result"}, +"Sample Scan" : {"image":"ex_scan.png","image_text":"Sample Scan"}, +"Scan" : {"image":"ex_scan.png","image_text":"Scan"}, +"Seek" : {"image":"ex_seek.png","image_text":"Seek"}, +"SetOp" : function(data) { + var strategy = data['Strategy'], + command = data['Command']; + + if(strategy == "Hashed") { + if(command.startsWith("Intersect")) { + if(command == "Intersect All") + return {"image":"ex_hash_setop_intersect_all.png","image_text":"Hashed Intersect All"}; + return {"image":"ex_hash_setop_intersect.png","image_text":"Hashed Intersect"}; + } + else if (command.startsWith("Except")) { + if(command == "Except All") + return {"image":"ex_hash_setop_except_all.png","image_text":"Hashed Except All"}; + return {"image":"ex_hash_setop_except.png","image_text":"Hash Except"}; + } + return {"image":"ex_hash_setop_unknown.png","image_text":"Hashed SetOp Unknown"}; + } + return {"image":"ex_setop.png","image_text":"SetOp"}; +}, +"Seq Scan": function(data) { + return {"image":"ex_scan.png","image_text":data['Relation Name']}; +}, +"Subquery Scan" : {"image":"ex_subplan.png","image_text":"SubQuery Scan"}, +"Sort" : {"image":"ex_sort.png","image_text":"Sort"}, +"Tid Scan" : {"image":"ex_tid_scan.png","image_text":"Tid Scan"}, +"Unique" : {"image":"ex_unique.png","image_text":"Unique"}, +"Values Scan" : {"image":"ex_values_scan.png","image_text":"Values Scan"}, +"WindowAgg" : {"image":"ex_window_aggregate.png","image_text":"Window Aggregate"}, +"WorkTable Scan" : {"image":"ex_worktable_scan.png","image_text":"WorkTable Scan"}, +"Undefined" : {"image":"ex_unknown.png","image_text":"Undefined"}, +} + +// Some predefined constants used to calculate image location and its border +var pWIDTH = pHEIGHT = 100. + IMAGE_WIDTH = IMAGE_HEIGHT = 50; +var offsetX = 200, + offsetY = 60; +var ARROW_WIDTH = 10, + ARROW_HEIGHT = 10, + DEFAULT_ARROW_SIZE = 2; +var TXT_ALLIGN = 5, + TXT_SIZE = "15px"; +var TOTAL_WIDTH = undefined, + TOTAL_HEIGHT = undefined; +var xMargin = 25, + yMargin = 25; +var MIN_ZOOM_FACTOR = 0.01, + MAX_ZOOM_FACTOR = 2, + INIT_ZOOM_FACTOR = 1; + ZOOM_RATIO = 0.05; + + +// Backbone model for each plan property of input JSON object +var PlanModel = Backbone.Model.extend({ + defaults: { + "Plans": [], + level: [], + "image": undefined, + "image_text": undefined, + xpos: undefined, + ypos: undefined, + width: pWIDTH, + height: pHEIGHT + }, + parse: function(data) { + var idx = 1, + lvl = data.level = data.level || [idx], + plans = [], + node_type = data['Node Type'], + // Calculating relative xpos of current node from top node + xpos = data.xpos = data.xpos - pWIDTH, + // Calculating relative ypos of current node from top node + ypos = data.ypos, + maxChildWidth = 0; + + data['width'] = pWIDTH; + data['height'] = pHEIGHT; + + /* + * calculating xpos, ypos, width and height if current node is a subplan + */ + if (data['Parent Relationship'] === "SubPlan") { + data['width'] += (xMargin * 2) + (xMargin / 2); + data['height'] += (yMargin * 2); + data['ypos'] += yMargin; + xpos -= xMargin; + ypos += yMargin; + } + + if(node_type.startsWith("(slice")) + node_type = node_type.substring(0,7); + + // Get the image information for current node + var mapperObj = (_.isFunction(imageMapper[node_type]) && + imageMapper[node_type].apply(undefined, [data])) || + imageMapper[node_type] || 'Undefined'; + + data["image"] = mapperObj["image"]; + data["image_text"] = mapperObj["image_text"]; + + // Start calculating xpos, ypos, width and height for child plans if any + if ('Plans' in data) { + + data['width'] += offsetX; + + _.each(data['Plans'], function(p) { + var level = _.clone(lvl), + plan = new PlanModel(); + + level.push(idx); + plan.set(plan.parse(_.extend( + p, { + "level": level, + xpos: xpos - offsetX, + ypos: ypos + }))); + + if (maxChildWidth < plan.get('width')) { + maxChildWidth = plan.get('width'); + } + + var childHeight = plan.get('height'); + + if (idx !== 1) { + data['height'] = data['height'] + childHeight + offsetY; + } else if (childHeight > data['height']) { + data['height'] = childHeight; + } + ypos += childHeight + offsetY; + + plans.push(plan); + idx++; + }); + } + + // Final Width and Height of current node + data['width'] += maxChildWidth; + data['Plans'] = plans; + + return data; + }, + + /* + * Required to parse and include non-default params of + * plan into backbone model + */ + toJSON: function(non_recursive) { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (non_recursive) { + delete res['Plans']; + } else { + var plans = []; + _.each(res['Plans'], function(p) { + plans.push(p.toJSON()); + }); + res['Plans'] = plans; + } + return res; + }, + + // Draw an arrow to parent node + drawPolyLine: function(g, startX, startY, endX, endY, opts, arrowOpts) { + // Calculate end point of first starting straight line (startx1, starty1) + // Calculate start point of 2nd straight line (endx1, endy1) + var midX1 = startX + ((endX - startX) / 3), + midX2 = startX + (2 * ((endX - startX) / 3)); + + //create arrow head + var arrow = g.polygon( + [0, ARROW_HEIGHT, + (ARROW_WIDTH / 2),ARROW_HEIGHT, + (ARROW_HEIGHT / 4), 0, + 0, ARROW_WIDTH] + ).transform("r90"); + var marker = arrow.marker( + 0, 0, ARROW_WIDTH, ARROW_HEIGHT, 0, (ARROW_WIDTH / 2) + ).attr(arrowOpts); + + // First straight line + g.line( + startX, startY, midX1, startY + ).attr(opts); + + // Diagonal line + g.line( + midX1-1, startY, midX2, endY + ).attr(opts); + + // Last straight line + var line = g.line( + midX2, endY, endX, endY + ).attr(opts); + line.attr({markerEnd: marker}) + }, + + // Draw image, its name and its tooltip + draw: function(s, xpos, ypos, pXpos, pYpos, graphContainer, toolTipContainer) { + var g = s.g(); + var currentXpos = xpos + this.get('xpos') , + currentYpos = ypos + this.get('ypos'), + isSubPlan = (this.get('Parent Relationship') === "SubPlan"); + + // Draw the subplan rectangle + if (isSubPlan) { + g.rect( + currentXpos - this.get('width') + pWIDTH + xMargin, + currentYpos - yMargin, + this.get('width') - xMargin, + this.get('height'), 5 + ).attr({ + stroke: '#444444', + 'strokeWidth': 1.2, + fill: 'gray', + fillOpacity: 0.2 + }); + + //provide subplan name + var text = g.text( + currentXpos + pWIDTH - ( this.get('width') / 2) - xMargin, + currentYpos + pHEIGHT - (this.get('height') / 2) - yMargin, + this.get('Subplan Name') + ).attr({ + fontSize: TXT_SIZE, "text-anchor":"start", + fill: 'red' + }); + } + + // Draw the actual image for current node + var image = g.image( + pgExplain.prefix + this.get('image'), + currentXpos + (pWIDTH - IMAGE_WIDTH) / 2, + currentYpos + (pHEIGHT - IMAGE_HEIGHT) / 2, + IMAGE_WIDTH, + IMAGE_HEIGHT + ); + + // Draw tooltip + var image_data = this.toJSON(); + image.mouseover(function(evt){ + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + var tooltip = $('<table></table>',{ + class: "pgadmin-tooltip-table" + }).appendTo(toolTipContainer); + _.each(image_data, function(value,key) { + if(key !== 'image' && key !== 'Plans' && + key !== 'level' && key !== 'image' && + key !== 'image_text' && key !== 'xpos' && + key !== 'ypos' && key !== 'width' && + key !== 'height') { + tooltip.append( '<tr><td class="label explain-tooltip">' + key + '</td><td class="label explain-tooltip-val">' + value + '</td></tr>' ); + }; + }); + + var zoomFactor = graphContainer.data('zoom-factor'); + + // Calculate co-ordinates for tooltip + var toolTipX = ((currentXpos + pWIDTH) * zoomFactor - graphContainer.scrollLeft()); + var toolTipY = ((currentYpos + pHEIGHT) * zoomFactor - graphContainer.scrollTop()); + + // Recalculate x.y if tooltip is going out of screen + if(graphContainer.width() < (toolTipX + toolTipContainer[0].clientWidth)) + toolTipX -= (toolTipContainer[0].clientWidth + (pWIDTH*zoomFactor)); + //if(document.children[0].clientHeight < (toolTipY + toolTipContainer[0].clientHeight)) + if(graphContainer.height() < (toolTipY + toolTipContainer[0].clientHeight)) + toolTipY -= (toolTipContainer[0].clientHeight + ((pHEIGHT/2)*zoomFactor)); + + toolTipX = toolTipX < 0 ? 0 : (toolTipX); + toolTipY = toolTipY < 0 ? 0 : (toolTipY); + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({'opacity': '0.8'}); + toolTipContainer.css('left', toolTipX); + toolTipContainer.css( 'top', toolTipY); + }); + + // Remove tooltip when mouse is out from node's area + image.mouseout(function() { + toolTipContainer.empty(); + toolTipContainer.css({'opacity': '0'}); + toolTipContainer.css('left', 0); + toolTipContainer.css( 'top', 0); + }); + + // Draw text below the node + var label = g.g(); + g.multitext( + currentXpos + (pWIDTH / 2), + currentYpos + pHEIGHT - TXT_ALLIGN, + this.get('image_text'), + 150, + {"font-size": TXT_SIZE ,"text-anchor":"middle"} + ); + + // Draw Arrow to parent only its not the first node + if (!_.isUndefined(pYpos)) { + var startx = currentXpos + pWIDTH; + var starty = currentYpos + (pHEIGHT / 2); + var endx = pXpos - ARROW_WIDTH; + var endy = pYpos + (pHEIGHT / 2); + var start_cost = this.get("Startup Cost"), + total_cost = this.get("Total Cost"); + var arrow_size = DEFAULT_ARROW_SIZE; + // Calculate arrow width according to cost of a particular plan + if(start_cost != undefined && total_cost != undefined) { + var arrow_size = Math.round(Math.log((start_cost+total_cost)/2 + start_cost)); + arrow_size = arrow_size < 1 ? 1 : arrow_size > 10 ? 10 : arrow_size; + } + + + var arrow_view_box = [0, 0, 2*ARROW_WIDTH, 2*ARROW_HEIGHT]; + var opts = {stroke: "#000000", strokeWidth: arrow_size + 1}, + subplanOpts = {stroke: "#866486", strokeWidth: arrow_size + 1}, + arrowOpts = {viewBox: arrow_view_box.join(" ")}; + + // Draw an arrow from current node to its parent + this.drawPolyLine( + g, startx, starty, endx, endy, + isSubPlan ? subplanOpts : opts, arrowOpts + ); + } + + var plans = this.get('Plans'); + + // Draw nodes for current plan's children + _.each(plans, function(p) { + p.draw(s, xpos, ypos, currentXpos, currentYpos, graphContainer, toolTipContainer); + }); + } +}); + +// Main backbone model to store JSON object +var MainPlanModel = Backbone.Model.extend({ + defaults: { + "Plan": undefined, + xpos: 0, + ypos: 0, + }, + initialize: function() { + this.set("Plan", new PlanModel()); + }, + + // Parse the JSON data and fetch its children plans + parse: function(data) { + if (data && 'Plan' in data) { + var plan = this.get("Plan"); + plan.set( + plan.parse( + _.extend( + data['Plan'], { + xpos: 0, + ypos: 0 + }))); + + data['xpos'] = 0; + data['ypos'] = 0; + data['width'] = plan.get('width') + (xMargin * 2); + data['height'] = plan.get('height') + (yMargin * 2); + + delete data['Plan']; + } + + return data; + }, + toJSON: function() { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (res.Plan) { + res.Plan = res.Plan.toJSON(); + } + + return res; + }, + draw: function(s, xpos, ypos, graphContainer, toolTipContainer) { + var g = s.g(); + + //draw the border + g.rect( + 0, 0, this.get('width') - 10, this.get('height') - 10, 5 + ).attr({ + stroke: '#FFEBCD', 'strokeWidth': 1.2, + fill: '#FFF8DC', fillOpacity: 0.5 + }); + + //Fetch total width, height + TOTAL_WIDTH = this.get('width'); + TOTAL_HEIGHT = this.get('height'); + var plan = this.get('Plan'); + + //Draw explain graph + plan.draw(g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer); + } +}); + +// Parse and draw full graphical explain +_.extend( + pgExplain, { + // Assumption container is a jQuery object + DrawJSONPlan: function(container, plan) { + var my_plans = []; + container.empty(); + var curr_zoom_factor = 1.0; + + var zoomArea =$('<div></div>', { + class: 'pg-explain-zoom-area btn-group', + role: 'group' + }).appendTo(container), + zoomInBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom in' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-search-plus' + })), + zoomToNormal = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom to original' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-arrows-alt' + })) + zoomOutBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom out' + }).appendTo(zoomArea).append( + $('<i></i>', { + class: 'fa fa-search-minus' + })); + + // Main div to be drawn all images on + var planDiv = $('<div></div>', + {class: "pgadmin-explain-container"} + ).appendTo(container), + // Div to draw tool-tip on + toolTip = $('<div></div>', + {id: "toolTip", + class: "pgadmin-explain-tooltip" + } + ).appendTo(container); + toolTip.empty(); + planDiv.data('zoom-factor', curr_zoom_factor); + + var w = 0, h = 0, + x = xMargin, h = yMargin; + + _.each(plan, function(p) { + var main_plan = new MainPlanModel(); + + // Parse JSON data to backbone model + main_plan.set(main_plan.parse(p)); + w = main_plan.get('width'); + h = main_plan.get('height'); + + var s = Snap(w, h), + $svg = $(s.node).detach(); + planDiv.append($svg); + + main_plan.draw(s, w - xMargin, yMargin, planDiv, toolTip); + + var initPanelWidth = planDiv.width(), + initPanelHeight = planDiv.height(); + + /* + * Scale graph in case its width is bigger than panel width + * in which the graph is displayed + */ + if(initPanelWidth < w) { + var width_ratio = initPanelWidth / w; + + curr_zoom_factor = width_ratio; + curr_zoom_factor = curr_zoom_factor < MIN_ZOOM_FACTOR ? MIN_ZOOM_FACTOR : curr_zoom_factor; + curr_zoom_factor = curr_zoom_factor > INIT_ZOOM_FACTOR ? INIT_ZOOM_FACTOR : curr_zoom_factor; + + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + } + + zoomInBtn.on('click', function(e){ + curr_zoom_factor = ((curr_zoom_factor + ZOOM_RATIO) > MAX_ZOOM_FACTOR) ? MAX_ZOOM_FACTOR : (curr_zoom_factor + ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomInBtn.blur(); + }); + + zoomOutBtn.on('click', function(e) { + curr_zoom_factor = ((curr_zoom_factor - ZOOM_RATIO) < MIN_ZOOM_FACTOR) ? MIN_ZOOM_FACTOR : (curr_zoom_factor - ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomOutBtn.blur(); + }); + + zoomToNormal.on('click', function(e) { + curr_zoom_factor = INIT_ZOOM_FACTOR; + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomToNormal.blur(); + }); + }); + } + }); + + return pgExplain; +}); diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index ddb9d8f..1366017 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -66,10 +66,53 @@ body { </button> <ul class="dropdown-menu dropdown-menu"> <li> + <a id="btn-explain" href="#"> + <span>{{ _('Explain') }}</span> + </a> + </li> + <li> + <a id="btn-explain-analyze" href="#"> + <span>{{ _('Explain analyze') }}</span> + </a> + </li> + <li class="divider"></li> + <li class="dropdown-submenu dropdown-submenu"> + <a href="#">{{ _('Explain Options') }}</a> + <ul class="dropdown-menu"> + <li> + <a id="btn-explain-verbose" href="#" class="noclose"> + <i class="explain-verbose fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Verbose') }} </span> + </a> + </li> + <li> + <a id="btn-explain-costs" href="#" class="noclose"> + <i class="explain-costs fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Costs') }} </span> + </a> + </li> + <li> + <a id="btn-explain-buffers" href="#" class="noclose"> + <i class="explain-buffers fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Buffers') }} </span> + </a> + </li> + <li> + <a id="btn-explain-timing" href="#" class="noclose"> + <i class="explain-timing fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Timing') }} </span> + </a> + </li> + </ul> + </li> + <li class="divider"></li> + <li> <a id="btn-auto-commit" href="#"> <i class="auto-commit fa fa-check" aria-hidden="true"></i> <span> {{ _('Auto-Commit') }} </span> </a> + </li> + <li> <a id="btn-auto-rollback" href="#"> <i class="auto-rollback fa fa-check visibility-hidden" aria-hidden="true"></i> <span> {{ _('Auto-Rollback') }} </span> diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index dee3ea1..6db04cb 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -236,3 +236,10 @@ .CodeMirror-foldgutter-folded:after { content: "\25B6"; } + + +.sql-editor-explain { + height: 100%; + width: 100%; + overflow: auto; +} diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index ee533a1..aeb1fdd 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -1,9 +1,8 @@ define( - ['jquery', 'underscore', 'alertify', 'pgadmin', 'backbone', 'backgrid', 'codemirror', - 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line', - 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', 'codemirror/addon/fold/pgadmin-sqlfoldcode', - 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter', - 'bootstrap', 'pgadmin.browser', 'wcdocker'], + ['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin', 'pgadmin.misc.explain', + 'backbone', 'backgrid', 'codemirror', 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', + 'codemirror/addon/selection/active-line', 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', + 'backgrid.filter', 'bootstrap', 'pgadmin.browser', 'wcdocker'], function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) { // Some scripts do export their object in the window only. @@ -161,6 +160,12 @@ define( "click #btn-auto-rollback": "on_auto_rollback", "click #btn-clear-history": "on_clear_history", "click .noclose": 'do_not_close_menu', + "click #btn-explain": "on_explain", + "click #btn-explain-analyze": "on_explain_analyze", + "click #btn-explain-verbose": "on_explain_verbose", + "click #btn-explain-costs": "on_explain_costs", + "click #btn-explain-buffers": "on_explain_buffers", + "click #btn-explain-timing": "on_explain_timing", "change .limit": "on_limit_change" }, @@ -247,7 +252,7 @@ define( height:'100%', isCloseable: false, isPrivate: true, - content: '<div class="sql-editor-explian"></div>' + content: '<div class="sql-editor-explain"></div>' }) var messages = new pgAdmin.Browser.Panel({ @@ -639,6 +644,79 @@ define( self.handler ); }, + + // Callback function for explain button click. + on_explain: function() { + var self = this; + + // Trigger the explain signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain', + self, + self.handler + ); + }, + + // Callback function for explain analyze button click. + on_explain_analyze: function() { + var self = this; + + // Trigger the explain analyze signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-analyze', + self, + self.handler + ); + }, + + // Callback function for explain option "verbose" button click + on_explain_verbose: function() { + var self = this; + + // Trigger the explain "verbose" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-verbose', + self, + self.handler + ); + }, + + // Callback function for explain option "costs" button click + on_explain_costs: function() { + var self = this; + + // Trigger the explain "costs" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-costs', + self, + self.handler + ); + }, + + // Callback function for explain option "buffers" button click + on_explain_buffers: function() { + var self = this; + + // Trigger the explain "buffers" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-buffers', + self, + self.handler + ); + }, + + // Callback function for explain option "timing" button click + on_explain_timing: function() { + var self = this; + + // Trigger the explain "timing" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-timing', + self, + self.handler + ); + }, + do_not_close_menu: function(ev) { ev.stopPropagation(); } @@ -703,6 +781,12 @@ define( self.on('pgadmin-sqleditor:button:download', self._download, self); self.on('pgadmin-sqleditor:button:auto_rollback', self._auto_rollback, self); self.on('pgadmin-sqleditor:button:auto_commit', self._auto_commit, self); + self.on('pgadmin-sqleditor:button:explain', self._explain, self); + self.on('pgadmin-sqleditor:button:explain-analyze', self._explain_analyze, self); + self.on('pgadmin-sqleditor:button:explain-verbose', self._explain_verbose, self); + self.on('pgadmin-sqleditor:button:explain-costs', self._explain_costs, self); + self.on('pgadmin-sqleditor:button:explain-buffers', self._explain_buffers, self); + self.on('pgadmin-sqleditor:button:explain-timing', self._explain_timing, self); if (self.is_query_tool) { self.gridView.query_tool_obj.refresh(); @@ -948,10 +1032,24 @@ define( var message = 'Total query runtime: ' + self.total_time + '\n' + self.rows_affected + ' rows retrieved.'; $('.sql-editor-message').text(message); - // Add the data to the collection and render the grid. - self.collection.add(data.result, {parse: true}); - self.gridView.render_grid(self.collection, self.columns); - self.gridView.data_output_panel.focus(); + /* Add the data to the collection and render the grid. + * In case of Explain draw the graph on explain panel + * and add json formatted data to collection and render. + */ + var explain_data_array = []; + if('QUERY PLAN' in data.result[0] && _.isObject(data.result[0]['QUERY PLAN'])) { + var explain_data = {'QUERY PLAN' : JSON.stringify(data.result[0]['QUERY PLAN'], null, 2)}; + explain_data_array.push(explain_data); + self.gridView.explain_panel.focus(); + pgExplain.DrawJSONPlan($('.sql-editor-explain'), data.result[0]['QUERY PLAN']); + self.collection.add(explain_data_array, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + } + else { + self.collection.add(data.result, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + self.gridView.data_output_panel.focus(); + } // Hide the loading icon self.trigger('pgadmin-sqleditor:loading-icon:hide'); @@ -1700,7 +1798,7 @@ define( // This function will fetch the sql query from the text box // and execute the query. - _execute: function () { + _execute: function (explain_prefix) { var self = this, sql = '', history_msg = ''; @@ -1719,6 +1817,17 @@ define( else sql = self.gridView.query_tool_obj.getValue(); + // If it is an empty query, do nothing. + if (sql.length <= 0) return; + + self.trigger( + 'pgadmin-sqleditor:loading-icon:show', + '{{ _('Initializing the query execution!') }}' + ); + + if (explain_prefix != undefined) + sql = explain_prefix + ' ' + sql; + self.query_start_time = new Date(); self.query = sql; self.rows_affected = 0; @@ -2037,6 +2146,66 @@ define( alertify.alert('Auto Commit Error', msg); } }); + }, + + // This function will + _explain: function() { + var self = this; + var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + // No need to check for buffers and timing option value in explain + var explain_query = 'EXPLAIN (FORMAT JSON, ANALYZE OFF, VERBOSE %s, COSTS %s, BUFFERS OFF, TIMING OFF) '; + explain_query = S(explain_query).sprintf(verbose, costs).value(); + self._execute(explain_query); + }, + + // This function will + _explain_analyze: function() { + var self = this;var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var buffers = $('.explain-buffers').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var timing = $('.explain-timing').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + var explain_query = 'Explain (FORMAT JSON, ANALYZE ON, VERBOSE %s, COSTS %s, BUFFERS %s, TIMING %s) '; + explain_query = S(explain_query).sprintf(verbose, costs, buffers, timing).value(); + self._execute(explain_query); + }, + + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + if ($('.explain-verbose').hasClass('visibility-hidden') === true) + $('.explain-verbose').removeClass('visibility-hidden'); + else { + $('.explain-verbose').addClass('visibility-hidden'); + } + }, + + // This function will toggle "costs" option in explain + _explain_costs: function() { + if ($('.explain-costs').hasClass('visibility-hidden') === true) + $('.explain-costs').removeClass('visibility-hidden'); + else { + $('.explain-costs').addClass('visibility-hidden'); + } + }, + + // This function will toggle "buffers" option in explain + _explain_buffers: function() { + if ($('.explain-buffers').hasClass('visibility-hidden') === true) + $('.explain-buffers').removeClass('visibility-hidden'); + else { + $('.explain-buffers').addClass('visibility-hidden'); + } + }, + + // This function will toggle "timing" option in explain + _explain_timing: function() { + if ($('.explain-timing').hasClass('visibility-hidden') === true) + $('.explain-timing').removeClass('visibility-hidden'); + else { + $('.explain-timing').addClass('visibility-hidden'); + } } } ); ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-10 09:24 Akshay Joshi <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Akshay Joshi @ 2016-05-10 09:24 UTC (permalink / raw) To: Sanket Mehta <[email protected]>; +Cc: pgadmin-hackers Hi Sanket On Tue, May 10, 2016 at 12:21 PM, Sanket Mehta <sanket.mehta@enterprisedb .com> wrote: > Hi, > > As previous patch was not applicable to latest pgadmin4 source code, here > is the new patch accommodating latest code. > Please do review it and send comments. > Following is my review comments - Remove Demo and sample code which you have used for testing before integration. - Facing issue to open QueryTool as there is some problem in require module. - Please add 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', 'codemirror/addon/fold/pgadmin-sqlfoldcode' files which has been removed from your patch. - Remove below code from sqleditor.js which is duplicated in _execute function - - self.trigger( - 'pgadmin-sqleditor:loading-icon:show', - '{{ _('Initializing the query execution!') }}' - ) - Clear the existing contents of the Explain tab when execute the query without explain. - If schema name is exists then please prefix the schema name to the node. - Please check the data is available before working on it in sqleditor.js at line no 1043 inside _render(). In case of "View Data" it throws an error. > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > > On Mon, May 9, 2016 at 11:56 PM, Sanket Mehta < > [email protected]> wrote: > >> Hi, >> >> Please ignore previous patch as there was an error in it. >> >> Error: >> Tooltip was not getting disappear when user moves cursor out of image. >> >> I have attached a proper patch with this mail. >> Please consider it for testing. >> >> Regards, >> Sanket Mehta >> Sr Software engineer >> Enterprisedb >> >> On Mon, May 9, 2016 at 8:49 PM, Sanket Mehta < >> [email protected]> wrote: >> >>> Hi, >>> >>> PFA revised patch according to Ashesh's comments. >>> Please find my response inline. >>> >>> I am currently adding minimap feature in graphical explain. >>> I will send a new patch for the same. >>> >>> Regards, >>> Sanket Mehta >>> Sr Software engineer >>> Enterprisedb >>> >>> On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi < >>> [email protected]> wrote: >>> >>>> Hi Sanket, >>>> >>>> Please find the review comments. >>>> - Please add the missing 'explain.css'. >>>> >>> Done >>> >>>> - The application should be smart enough to handle conflict in options. >>>> i.e. >>>> Buffer is not a valid options without EXPLAIN ANALYZE. >>>> >>> Done >>> >>>> - A statement having EXPLAIN keywords with different format should at >>>> least render the output in the data-grid. >>>> i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; >>>> >>> Done >>> >>>> - Please use the keywords used in the EXPLAIN statement in capital. >>>> >>> Done >>> >>>> - Explain should not work with empty string. >>>> >>> Done >>> >>>> - Font size in the tooltip is very small. >>>> >>> Done >>> >>>> >>>> >>> - Smoothing the zoom functionality. >>>> >>> Minimap will be added and zoom functionality will be removed. So it is >>> ignored. >>> >>> - Arrow marker is hardly visible. >>>> >>> Done. >>> >>>> >>>> >>>> -- >>>> >>>> Thanks & Regards, >>>> >>>> Ashesh Vashi >>>> EnterpriseDB INDIA: Enterprise PostgreSQL Company >>>> <http://www.enterprisedb.com; >>>> >>>> >>>> *http://www.linkedin.com/in/asheshvashi* >>>> <http://www.linkedin.com/in/asheshvashi; >>>> >>>> On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < >>>> [email protected]> wrote: >>>> >>>>> Hi, >>>>> >>>>> This patch includes the patch sent earlier for stand alone graphical >>>>> explain. >>>>> >>>>> And also "horizontal lines are not proper" bug is fixed in the same >>>>> which was reported by Dave in previous patch. >>>>> >>>>> Regards, >>>>> Sanket Mehta >>>>> Sr Software engineer >>>>> Enterprisedb >>>>> >>>>> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Team, >>>>>> >>>>>> PFA the first patch for graphical explain integrated in sql editor. >>>>>> >>>>>> Below are the few things which are different from previous patch >>>>>> which was sent for stand alone graphical explain. >>>>>> >>>>>> - Now user can select Explain/Explain Analyze with four optional >>>>>> properties (Verbose, costs, timing and buffers) >>>>>> >>>>>> - Initially graph will be scale (according to only its width not >>>>>> height) to fit to screen so no blank space will be there in case of very >>>>>> large graph. >>>>>> >>>>>> - Along with zoom in/out button, "zoom to original" button is also >>>>>> provided, by clicking on which graph will be scale to its original size >>>>>> (not same as initial one which is according to screen size). >>>>>> >>>>>> Please do review this patch and let me know in case you have any >>>>>> comments. >>>>>> >>>>>> >>>>>> Regards, >>>>>> Sanket Mehta >>>>>> Sr Software engineer >>>>>> Enterprisedb >>>>>> >>>>> >>>>> >>>> >>> >> > > > -- > Sent via pgadmin-hackers mailing list ([email protected]) > To make changes to your subscription: > http://www.postgresql.org/mailpref/pgadmin-hackers > > -- *Akshay Joshi* *Principal Software Engineer * *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-13 10:25 Sanket Mehta <[email protected]> parent: Akshay Joshi <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-05-13 10:25 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi, Revised patch is attached Response in inline. Regards, Sanket Mehta Sr Software engineer Enterprisedb On Tue, May 10, 2016 at 2:54 PM, Akshay Joshi <[email protected] > wrote: > Hi Sanket > > On Tue, May 10, 2016 at 12:21 PM, Sanket Mehta <sanket.mehta@enterprisedb > .com> wrote: > >> Hi, >> >> As previous patch was not applicable to latest pgadmin4 source code, here >> is the new patch accommodating latest code. >> Please do review it and send comments. >> > > Following is my review comments > > - Remove Demo and sample code which you have used for testing before > integration. > > Fixes > > - Facing issue to open QueryTool as there is some problem in require > module. > > Fixed > > - Please add 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', > 'codemirror/addon/fold/pgadmin-sqlfoldcode' files which has been > removed from your patch. > > Fixed > > - Remove below code from sqleditor.js which is duplicated in _execute > function > - > - self.trigger( > - 'pgadmin-sqleditor:loading-icon:show', > - '{{ _('Initializing the query execution!') }}' > - ) > > Fixed > > - Clear the existing contents of the Explain tab when execute the > query without explain. > > Fixed > > - If schema name is exists then please prefix the schema name to the > node. > > Fixed > > - Please check the data is available before working on it in sqleditor. > js at line no 1043 inside _render(). In case of "View Data" it throws > an error. > > Fixed > > >> >> Regards, >> Sanket Mehta >> Sr Software engineer >> Enterprisedb >> >> On Mon, May 9, 2016 at 11:56 PM, Sanket Mehta < >> [email protected]> wrote: >> >>> Hi, >>> >>> Please ignore previous patch as there was an error in it. >>> >>> Error: >>> Tooltip was not getting disappear when user moves cursor out of image. >>> >>> I have attached a proper patch with this mail. >>> Please consider it for testing. >>> >>> Regards, >>> Sanket Mehta >>> Sr Software engineer >>> Enterprisedb >>> >>> On Mon, May 9, 2016 at 8:49 PM, Sanket Mehta < >>> [email protected]> wrote: >>> >>>> Hi, >>>> >>>> PFA revised patch according to Ashesh's comments. >>>> Please find my response inline. >>>> >>>> I am currently adding minimap feature in graphical explain. >>>> I will send a new patch for the same. >>>> >>>> Regards, >>>> Sanket Mehta >>>> Sr Software engineer >>>> Enterprisedb >>>> >>>> On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi < >>>> [email protected]> wrote: >>>> >>>>> Hi Sanket, >>>>> >>>>> Please find the review comments. >>>>> - Please add the missing 'explain.css'. >>>>> >>>> Done >>>> >>>>> - The application should be smart enough to handle conflict in options. >>>>> i.e. >>>>> Buffer is not a valid options without EXPLAIN ANALYZE. >>>>> >>>> Done >>>> >>>>> - A statement having EXPLAIN keywords with different format should at >>>>> least render the output in the data-grid. >>>>> i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; >>>>> >>>> Done >>>> >>>>> - Please use the keywords used in the EXPLAIN statement in capital. >>>>> >>>> Done >>>> >>>>> - Explain should not work with empty string. >>>>> >>>> Done >>>> >>>>> - Font size in the tooltip is very small. >>>>> >>>> Done >>>> >>>>> >>>>> >>>> - Smoothing the zoom functionality. >>>>> >>>> Minimap will be added and zoom functionality will be removed. So it is >>>> ignored. >>>> >>>> - Arrow marker is hardly visible. >>>>> >>>> Done. >>>> >>>>> >>>>> >>>>> -- >>>>> >>>>> Thanks & Regards, >>>>> >>>>> Ashesh Vashi >>>>> EnterpriseDB INDIA: Enterprise PostgreSQL Company >>>>> <http://www.enterprisedb.com; >>>>> >>>>> >>>>> *http://www.linkedin.com/in/asheshvashi* >>>>> <http://www.linkedin.com/in/asheshvashi; >>>>> >>>>> On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi, >>>>>> >>>>>> This patch includes the patch sent earlier for stand alone graphical >>>>>> explain. >>>>>> >>>>>> And also "horizontal lines are not proper" bug is fixed in the same >>>>>> which was reported by Dave in previous patch. >>>>>> >>>>>> Regards, >>>>>> Sanket Mehta >>>>>> Sr Software engineer >>>>>> Enterprisedb >>>>>> >>>>>> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Team, >>>>>>> >>>>>>> PFA the first patch for graphical explain integrated in sql editor. >>>>>>> >>>>>>> Below are the few things which are different from previous patch >>>>>>> which was sent for stand alone graphical explain. >>>>>>> >>>>>>> - Now user can select Explain/Explain Analyze with four optional >>>>>>> properties (Verbose, costs, timing and buffers) >>>>>>> >>>>>>> - Initially graph will be scale (according to only its width not >>>>>>> height) to fit to screen so no blank space will be there in case of very >>>>>>> large graph. >>>>>>> >>>>>>> - Along with zoom in/out button, "zoom to original" button is also >>>>>>> provided, by clicking on which graph will be scale to its original size >>>>>>> (not same as initial one which is according to screen size). >>>>>>> >>>>>>> Please do review this patch and let me know in case you have any >>>>>>> comments. >>>>>>> >>>>>>> >>>>>>> Regards, >>>>>>> Sanket Mehta >>>>>>> Sr Software engineer >>>>>>> Enterprisedb >>>>>>> >>>>>> >>>>>> >>>>> >>>> >>> >> >> >> -- >> Sent via pgadmin-hackers mailing list ([email protected]) >> To make changes to your subscription: >> http://www.postgresql.org/mailpref/pgadmin-hackers >> >> > > > -- > *Akshay Joshi* > *Principal Software Engineer * > > > > *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* > -- Sent via pgadmin-hackers mailing list ([email protected]) To make changes to your subscription: http://www.postgresql.org/mailpref/pgadmin-hackers Attachments: [text/x-patch] integrated_graphical_explainV6.patch (496.6K, 3-integrated_graphical_explainV6.patch) download | inline diff: diff --git a/web/pgadmin/misc/__init__.py b/web/pgadmin/misc/__init__.py index f461cbe..125c44c 100644 --- a/web/pgadmin/misc/__init__.py +++ b/web/pgadmin/misc/__init__.py @@ -6,28 +6,52 @@ # This software is released under the PostgreSQL Licence # ########################################################################## - """A blueprint module providing utility functions for the application.""" -import datetime -from flask import session, current_app +from flask import url_for, render_template from pgadmin.utils import PgAdminModule import pgadmin.utils.driver as driver +import config MODULE_NAME = 'misc' -# Initialise the module -blueprint = PgAdminModule(MODULE_NAME, __name__, - url_prefix='') - -########################################################################## -# A special URL used to "ping" the server -########################################################################## - +class MiscModule(PgAdminModule): + + def get_own_javascripts(self): + scripts = [{ + 'name': 'pgadmin.misc.explain', + 'path': url_for('misc.index') + 'explain/explain', + 'preloaded': False + },{ + 'name': 'snap.svg', + 'path': url_for( + 'misc.static', filename='explain/js/' + ( + 'snap.svg' if config.DEBUG else 'snap.svg-min' + )), + 'preloaded': False + }] + return scripts + + def get_own_stylesheets(self): + stylesheets = [] + stylesheets.append(url_for('misc.static', filename='explain/css/explain.css')) + return stylesheets + + # Initialise the module +blueprint = MiscModule(MODULE_NAME, __name__, static_url_path="/static") + + ########################################################################## + # A special URL used to "ping" the server + ########################################################################## + [email protected]("/") +def index(): + return '' @blueprint.route("/ping", methods=('get', 'post')) def ping(): - """Generate a "PING" response to indicate that the server is alive.""" driver.ping() - return "PING" [email protected]("/explain/explain.js") +def explain_js(): + return render_template("explain/js/explain.js") diff --git a/web/pgadmin/misc/static/explain/css/explain.css b/web/pgadmin/misc/static/explain/css/explain.css new file mode 100644 index 0000000..49a4bc4 --- /dev/null +++ b/web/pgadmin/misc/static/explain/css/explain.css @@ -0,0 +1,56 @@ +.pg-explain-zoom-area { + position: absolute; + top: 5px; + left: 5px; + opacity: 0.5; + cursor: pointer; +} + +.pg-explain-zoom-btn { + top: 5px; + min-width: 25px; + cursor: pointer; + border: 1px solid transparent; +} + +.pg-explain-zoom-area:hover { + opacity: 1; +} + +.explain-tooltip { + display: table-cell; + text-align: left; + white-space: nowrap; + line-height: 10px !important; + padding: 2px !important; + font-size: small; +} + +td.explain-tooltip-val { + display: table-cell; + text-align: left; + white-space: pre-wrap; + font-size: smaller; +} + +.pgadmin-explain-tooltip { + position: absolute; + padding:5px; + border: 1px solid white; + opacity:0; + color: cornsilk; + background-color: #010125; +} + +.pgadmin-tooltip-table { + border-collapse: collapse; + border-spacing: 1px; + top: auto; + left: auto; +} + +.pgadmin-explain-container { + height: 100%; + width: 100%; + overflow: auto; +} \ No newline at end of file diff --git a/web/pgadmin/misc/static/explain/img/ex_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfe75d909f5092c4d3ba8978c75fbc57d7f606d GIT binary patch literal 574 zcmV-E0>S->P)<h;3K|Lk000e1NJLTq001%o001%w1^@s69zTe&00004b3#c}2nYxW zd<bNS00009a7bBm000fw000fw0YWI7cmMzZ8FWQhbW?9;ba!ELWdL_~cP?peYja~^ zaAhuUa%Y?FJQ@H10lP^=K~!jg?U_w#!!Qs=pNrR76nc`JAiEyfyPUu$F?5lg!9`tE zrVdorjI6O#*B=N1Q4~GTk7uODImZ$7QhEcqbb{2T!+^AsNlnvqz}0v!OZCpVcg+u) zSl03oH-ylcGy!)Fj09u=UN>$mMIX+&H|b<ajP!gzp{f<N2t38e1(}OYz(X)^Z9SDm zaL$Pb&;cXx85twc3D+9}YYwWtX(n61tgLAZVhA&A0ZDox`m}f_o&;Lp=3^|TZAm4? zB8D-uw2Hk&77xL~GD+H8Yh{L+-D~onRU64N$mC{z9Z`Z<4$%uyDn(tUuBBqiTE>@* zne6>YDVVIT^|Y|u&2%+YKxQ4H!ZKN8+Uk0kwJKPjW&<(>@$PjAe4RCOnSn%Nr0(=P zYi|fJ04V_hnL$cH0K3&%;sz_V=BgQD)cm$)2vvhs6@*_isdrBfc8kD{yg=7gktITF z+PGFu2!0OeLWgu>5LFp3D9xourL!bQu%a?wd{rRqFIvi++{=Q!&>aaV%KTa{dS;2c z$5o3IhEOTyT37x61pK30-JX4KbAS7Pk<5;R_SRus>jbGyCrEAj0!#X?PWurOy8r+H M07*qoM6N<$f>VU-$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_append.png b/web/pgadmin/misc/static/explain/img/ex_append.png new file mode 100644 index 0000000000000000000000000000000000000000..017a2068b735f13cb89a3bcb2832e5880d17df56 GIT binary patch literal 1162 zcmV;51a<p~P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(LcQrnzUg(&?|IPgRl@0p)bM7=>}tvEZ_4YI+3|bM?Sj$mrrz?7)b5hj z@2}zW1*hRn!RZ^W<6Fh+V#n(^x8+d2=WEC4a+aaNk2du1$nfm9@9MSh>9q3g#qH&> z?c}iR<FN7S!|>?B>));G-mL1~tMBB$>*k;D>$d6On&{t|?&h=S+m`0ol<eWI<I<1f z(2eQZsp{jL=-rs*){^1Oi|N^?<kgYn(~#oMjOf><@94Ab;k?JHb@1lE=hUR;)1&O& zx!}r)-o=I9!-U<zg67eo-^hpM&!OhgqTIiL<j$Y(=D_CCqwCqW<jtPr%%0=Rp4+{D z+PZy)sbo@(8Kui)sL*Ju)oiZXakAicwdHz}mC<Hv(aX&7yuR$dzwOS>^3l=q!NTst z#P8G8^VQY#$jI=?$??j|@!8t--ro1u*Y)Ay_q@IAr>W+ss^`DI?yaxsud(UH#qY<+ z@3pq;x47%Lx$M-`^vB2WiI(>{00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0zpYcK~zY`?U3tJ5>Xh&?SzGeqJ$LLD=fGO%SB*ek((>YO)i2W3vOk#CSYi4 znRfSIZ+9mfuyZIJXZldjhj-?kd4K0Q&oeUeU#e~(MZ}3i&`phI^cK3U)oRDk*qyt& zaWp=m*H5C!DTCo2!Xg@@(Kw2xO(xTQ^uTO3>(InQtyYhwW@dB-G{|N8&s`p=e<n^G z0<#v2W%goPDar;m`yB0nd8dnU0~WD(JRXZWy+HYV3x2Q%f<YFXp-`9`j6@<<8Ch7g z109S;oxp^{vG^dw8;L|H@Gk}eG_cV`k^ych7US{Aj}#QOtfZjT6pWn09q0KJ7I_Sc zh!gMP^;&1a=J(qj;9yzj3b;8go`O_5oyp=qCa3T%U!+JRLvo5(EXPASzgj5bk-lP+ zO0n@=u9Sw%YN1djA(xBgOQn1U)(VwM6_42b_BpvF*6CW8Q^eI2nT;%D%hhV_+8T4v zEISV?48yr0#q(+T{k3Ab2DQz)fOi2p8cn$56iaG~e0~Fpl}e)u^=7jv;1M>FxKwPp z(r9dgKt_How%TaO#{-achU4Ux__UIuSXNThl@v8W5U#DUt7}W#B5ow&NzYaPMkJm- z`+3#B5v1H~KNqnZ(M8-Adt7=qvQOWu;_p1vqZcA^BYthzl84euNfB}45NYSt?ruwJ zclP#POWpm0H;2+;tKB}5j=J6Bw-Oe4cXIOnRO+0aefTJS`uyeVj?_BsblTFl^ZkS4 zzljW=<qD1clll(R-{b2g;$(6F001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@z zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUh cIxsdXFf}?bFv^!ztN;K207*qoM6N<$g1#AbUjP6A literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_and.png b/web/pgadmin/misc/static/explain/img/ex_bmp_and.png new file mode 100644 index 0000000000000000000000000000000000000000..64d5869dcfcf9d94d031fa068cff93ea929180b2 GIT binary patch literal 1006 zcmV<K0}=d*P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004)P)t-smD2kF z003rd(R6flb#--ic6N7ncY1nyHi*G{dwYC*e13j@fPjF4f`WsCgM@^HhlhuVh=_}e zi;azqj*gCGmC%omkC2d%k&%&&j=z$UlEIHQm6er`lHGcqshOFXoSdAVo}QbW#Gjv^ zrlzK+r>D86a;T`NPQK>5s&lKWtGldpyRCMut*u(Y=dP}<ys&q#udltad8@4GzOs6W zx!ba`vSh{Rx3{;mwCZuo?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?Zd;v-NJ*w!S2S! z#*5VM-^PaD$cK{E@5aaP;L3^0%F2}3@Z-y#<IJAq&7R`WjpWXs%+2x5&hq8Zq2|$| z)6>(Y-ty(vljhW<)z#JK)upZ9^VHPy=+~y`*Qe^(w&~ia>DsB<+S=*ds_NXT>)W{8 z+}z#W-Rs`0?A^KE-rnrst?b~g?cclJ-uCR`ui@e0?BlTF;^Ob*zvboS@aDkq=fUUa z=jrL`@$1Cu>gw?D@bU5S^78WY^Yiuf_4fAm`1ttw`T70*{r~^}C9&%N00001bW%=J z06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0q;pfK~zY`?UY$l6G0S(b8}-Di3kcP z+Oo)^h$4bwltoqvL?DD{Mjf_nBqD~O2?A~ymixDzo*9a*Gm})MC?7Zv{c`K8Gv{>Q zvDq$ko~o9(s?QF(wL!N4k*52GJqwax@WJEtiUu~Rr}eShD?&VOcaK*pj!Vugb=sg# zfY{%@e)DeKes;iqrqk&yCPD_D!r-C^Nk4<GWMRlx_z0E==`xVDE_fnFj<OJC>PwuJ zQ#!=9lF84TBBa*NRjVOi9LP1IA^nW2-@@fKw*1L<;8opaGaip`h_l>+MlB1G6SG9S z=+u$;BX}4UBk&Ro<O=>E`h+(O1ZE*><<f@Dv{HsEI<ou#?nSH``|ZN(SURV-%r>Ht zNXoo1qP+&hYdgl><kJ{stMHBkrzooyKsJ^Ng_cqlS=#YAjp3zO3@bPinuH0(v@xPG z-th~(T!n2MS(<=x#ngpg%P%#>ef9pot6A9mcrN5H3(-xi$?R{pAeQfQB&8_Is%c|H zG5v{QDc(Jx{2HTgO)iJ4;r-tV>{PR?%CelW*cUn`^~2;*7z$c$rLkbz!Q>%$6)bF# zgDMhW1^r<X!9XBkv6Uy4*H)f(3HbeC^EY-H@%KXSjQLiI5MN;~GdYo*S;9V_FI=R? cF7zMiA0?@qIju>9W&i*H07*qoM6N<$f<qfLO8@`> literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png b/web/pgadmin/misc/static/explain/img/ex_bmp_heap.png new file mode 100644 index 0000000000000000000000000000000000000000..2657d8c39328bfc80751c60db9d3ab4341c0de35 GIT binary patch literal 1106 zcmV-Y1g-mtP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s00000 z003rd(Nc{WHi*Gol_FY@Wn`8)38~@|tKwvp&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPGu5^~NHbTAWN5AP#zUE86=}y7vTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q^_*?AyJGyuIvu(eH!N?S#?pz`^c> z)9|d;ZHv_Ik=5>!)$gv_amL5*l-Tf>+3~XAcCFUw%+2wj+wtexE9lxP&Cc@b+bZna zD(>4V@7yZ!+$!?iD)ihcx!dfw=Y00vDy`r1`Q0h{-6_=6^RD3Y``#)1-YNdxDZbwA zx$A$x-|oWT?z`@S?c-qY<6p($@9^Ybyzqqb<X`jTU&rI{$m8(y<zMvWU&`a~_2pmp z<zM*aU(4k2-rn~3=3n~eU(Mz6{N`W&=3mk0^3&+^^6H1w>GRa-^z`e8*6H;2>xcO3 zhu7-$`s|1O?1ujAhT-q`mEcQQ00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94 zoEQKA0&7V`K~zY`?Ud_N(?Ar(NfQ+@uBZsUQR*A(3k7^uiA_xlwb7<XX$T2Wl46zw z3Z<omf1TZggd}Y;GR`=D;C$H3?B=&;&b@cGr{_ffM12%iU&sC(Yu~pzN7RRBuO_}z z9SHSg=<4;C)SHp}k3Ldg#wI3zy8lp*uid=+whJ=U+k5r~HGFAc;3+jWJaTW6`U{t^ zEElbP-|8I2KEHnd^>^&(-vmu3&<E7Y<#G+wL{Y4Rx+F<;;36;16PJH@5PE-~#z=W; ziYWt;VNw#1SeBJN2=S2cA-lUa!Z3^o#8j#a5_H+w@gP!)Wi2G_L4sKv#G9fn%W}g- z`eRt9$y)*BIl%I*K9?(GoOF@xZQI4ZUy^0CDl3(yC(CW(0vV5!j_A!z8h-}~mT*$6 za2%)l5JX@-7#$sd_le%vpcj!ymO#PfbULko3dd#C2p5DnE;2^GRe;K6G8zcaf)Jd= zPSH>*C`D7%v}T}UXUKCdvcCQ&74!AQMsP2b2D)EWk&C8PTM^wqM7$}qY%Zrq%-GtR zg(zuUST%!@YA%<95iYB%7Gn28&1ADxp!<=IEX&Il;!V+l5Vj&_Y-#D(Gq$jB=z@FE z)OFo<X@_?I6h_E^1__=pLT79oBQrC<=I0lWMDj$zh?ucbsf$a&>(Y@0AyyV$hfa#N zVHoX*8Jn9s_Kewxb3cRzb}`Mpu<oOWZ+aR(egNk4c?ck1K*3ExD4Jn2MsLj~le1g2 zh42s<1wlYavFJkrE~R9$WV`UZ0SrM9%pelTlE5>D9%WyOJ=2@Tu2_G^GagZ~6a9ZW Y0Mz-{B6#`Cr~m)}07*qoM6N<$f){{JGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_index.png b/web/pgadmin/misc/static/explain/img/ex_bmp_index.png new file mode 100644 index 0000000000000000000000000000000000000000..23b9733b56792533e4db25ca9890a0a0140c6ff9 GIT binary patch literal 1172 zcmV;F1Z(?=P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004@P)t-s000{R z003rd(Nc{WHi*Gol_FY@Wn`8)45{LDla^$a&~c(UW|q;7j=#Z=Hh!USkCNSbo~bRg z<eQwtI=JPPu{MmZbjzYxL%irozv)iC=1#%sTEXX;ym+gu=v~C>iMiWk#pq(j>Y>D5 zYsctl$n2uVV6(L9Zp-X(%j|E>?xxITcFpXi!Q|V#etORA+r5d~zJR>F?0eDg-NAx` z(d~rM?%l(Kz`^c>)9|d;ZQjL&i`4Gl$A^*C?%>FXlGX37+HuCm@8HUbl-Tg$%!-%U z@#4;m<IJA2;C8Ln>CDaX<<6kv(T?ZZE6vXG=Fy>}-SXtrk>=B+^4u!t)TFuF?6>E9 zt>5$1)bp<3^XA!==+~zI-YMzWr@r3px$A%D+?T-L?&;d7!r<=c-k9s!x9Z%g?c-qY z<6p($@9N#Gyzqqc<X`FGo9x}X$K&wG<M7Jk@a*8N%jEIi-uC(CU(Mz6?BlTi=3nmO zz3t_((dY8+=Caf1^Y7)q^6H1w>GRa-^w#P0@aMtr>9p7C_3`P${_KYG?Z)Bn_g>Mo zbpQYW0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_00N9jL_t(Y$L*BsQxZ`a zhh26nvhB^vO1oLo-JmFv5|N5XBA|_nRxB8D7XcMR7F@v#0{+$QVK1_a?Bq1l^uhPT z*_pHZ%x|7^ezOAuC-YBckU%rovwx?vFI&Y|#D{0EroRzA2=QcObo3?hX8iu6kHpu> z>6stWH^k%XH}AeZ0vXY2wKs^dOT)uYiOI3?do#per1Wz++u7&Wi~K6S(tLjX{>v}T z;kSB{)N>E0r_<>=v>S~^8`><(wn0K(oX0MI??T9f0}>%=uh*M~Mn0c!0Gmiet6d28 z5R)PM`wD~wHX4nVRZ@0$Wk@2yLNyu+bs<U@5fNNE7R_?GyeA<;8Z@WzTMFbFpyAi& z{3=ViitBI*+1Zh$RI5#B7K_EbE|=Tb1ze}Y#UZ!0Nc6mdd9k!$QS|wISsB6+XdX;V zOuhR=Zf=sx+~8h})31g?q2dvUJcUEVlnj&w#N$ape-{qnT{4-vU{TAaQZ>biox#sZ z$i~K>oS5uhcm(RXT&@m##cZ|)wNxxtQMr8q$pr#|oL~`iI2^P}$JW;+qy$+HkJ#<B zO3K=rgfNiu%+AIjVz=9ZDji#0?I5jEsnmj63|UlYnl7kxY-Q!x9a~xwQW&NMl}LoH zKp`0P7y91*DTMI1AI2EY!p2zyEfzD?w_{TXnV<i;jEAu>1GLR%4T9fnRv_|@#p7Km zwAE@sh{;5$bc{nfE(~(vEeaGxB~?1MxOnW2@ran>r>FuX-EMcX-|cfhzPUN{^8+Rv z=Ja_Bx6xp5_UjnAz2I^!Y?C5FnM@`(xD9edkrH>g;)f}e$!P3B6fSzyF}>u%TO^%M mr}D&xdVb?7Cw4Ob-~0w&gyX$CR{j?N0000<MNUMnLSTYde~VB6 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_bmp_or.png b/web/pgadmin/misc/static/explain/img/ex_bmp_or.png new file mode 100644 index 0000000000000000000000000000000000000000..c22fc31eee32e53abf634278f9d57751181f15c0 GIT binary patch literal 685 zcmV;e0#f~nP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700030P)t-s00000 z003B6SY~U{Hi*GwmC%ijzrl|-kCNSbo~fFenwy-&xu<eYzUI5CbGxi`yRCLw!RNfN zcfGNBtE}k0vU-WR+hoP)v$X2Ey1H@8?Ap72dd}?Iy@}kufV{ozyuIz+!GeR)?cKtI zz`^c|)b8KLhTq7ClGX3V$M4|EiImvz<IA4o%%0@Up5oAr<j$YW&GF67^3l=J<<Oz# z(W0i_^5xc(=G3I;)upZ9^VHPy=+~y`*Qe^(w&~ia>DsC3+^Xu_s_Wah>)x#F-MQ@G zt?b~g?cclJ-uCR`uk7Qn@8rMa<mB+?!0_k6@$1Cw?CkIF@AUNa|NsAqxAFG?0004W zQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkPM@d9MR7l6|)NN0KU=#*mj$o+0 zXGv;SRwxw`6%>^SK@x>8z5V~+lCW40^I>$hY<=+l#CCS=?A!_rGtXZp&xOfP4=T~1 zLLuDg&VhK#Q3h9{B+&*8S6f~eBpML~p(b&^vn6@U$0T2m#b{8Z5cd4&_~MEE7O~-9 zf*=_4G_tn|`*$&UE0u;Z3AUi@Ws_kpcNvpsxCSJ7EW-w!ByJ(e*z+DnG*V#06sAdo z57R(x899zKpx?3pi_}}3HCVOj1h#=r;0$csmirZ0vT%(JY|HXz-k5KiT_1Ogc>-+% z*I2g=Ed#gZrj<t0Z!rv`Kl8@=x~{vp_eDR1riLU<*hLa;LR4I1uBNJPc4P0=>MO1> z^3%t=s-pBVfBn$JPrOoxdMEQgMkXTi54I4blS&e|kfbNeaxb$nGU<)Y^N;cg@O4qi TF88uo00000NkvXXu0mjfLbGwY literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png b/web/pgadmin/misc/static/explain/img/ex_broadcast_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..e99f57478842f61cf0582433b659d37f0c532d5c GIT binary patch literal 334 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_@3?!2S6O@1yXMj(LE06{PXIHn!e64$cEXI-` zzhDN3XE)M-9L@rd$YLPv0mg18v+aP48c!F;5RLO&CtC9zP~dS+JaMn}cL58V&ewnH znS#1o7niJ>^>*TX*`QzgMdD7POzPaTo+w<9uwpLL)1F%W#!IqdhoMSxhwp~0@cf02 zhkMjmROfZc`EZ)w`S;|i<*e@Qr8gQ^@9R11|6Rc8|AQ9IRLjSmUOFeWtM)%%ZozPh zRpl$&!*g?h?ocgpjVMV;EJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0 rRpn4L<mRVjrd2{T7+8WefK*!<m_an0njX3asDZ)L)z4*}Q$iB}@40B! literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_cte_scan.png b/web/pgadmin/misc/static/explain/img/ex_cte_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7e1d779372f7fd212d2096e7701b0f1af05a5297 GIT binary patch literal 1955 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_delete.png b/web/pgadmin/misc/static/explain/img/ex_delete.png new file mode 100644 index 0000000000000000000000000000000000000000..ca051cd5d01ee2f3ac17779b362999d82a9285b5 GIT binary patch literal 1129 zcmV-v1eW`WP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003^P)t-sKLD^> zTU+Qs2lh=8Hi*I5b0^MyED5RN(19;<mZ6f8lEIHQ*N;guwdHlD$Lf$-LA>b8qFCae zX-dH9$EtPXqi$Wq>SM<0Ysctl$n0**>~+oT+Pi++y?@)iiQK+`+`oW((eK>Bf`rlT z-NS=~)9~KJgx<x4-o}QE)b8KMhu_GEk=5?t$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc z&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+mlIGK+<<^tt)THOtrLN%f=Gm0!*QV&# zr{>z0>DZ^~*{J8-m+9K6>e;sG+p6o@x9HxP>fNgB+_>rBn(N-I?A^NS->vN4y6oVs z>f@a4-@EMLuI=Ev>g1j5;;-%DyzJw!?d7rW<i73ZvhL=y@8!Vo=D_dhv+wD(@aV$u z>B8{rw(;x4^6ka*?Z)%)$Yy(c-~a#s0d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkV znw%H_00Om1L_t(Y$L*8bdl^v_#f8bG-PLL%nhMc~q#`mQ2qBD7)FomPgc62MQMdg6 zk3DnFFeXNthkjrCko~Zp{O0Vn_M*|e%s-g7lsHRO4WY~igJFl-+ccRDsDn>t^C@+@ zx4(Z*ogcZ~Uny0@u)e--pf-`3sE>NR-c0Qve4jen-Zs0bzx2v0yz^33L*QXJ96n67 z-|vrMEC|8~Mm*0Cfcyr)IFAhP?`wTY`?t5ZJrIhyTpRdgGF}BjOnw=S3Z#aS8bOKz z2)SI2hh{Q9MZQla-3-V`zlMK|wO1@6q@DYg<e?sq#VQh#$r!5>kiFpjXD)tV7tH|- zs+Ce#@?tf9p@%c(J&3b~b$3yv?^<i0Wd?NOY>az?FosdP&5vMEuU5Oz<v6Z0{jh=o zomQ*WZOAT~qKnHCa6!L6FYiCcNQh7@l3<f{sKzcYIN<z#Z+<Q&%wTg<1P9CGU@I5F zAO{7nm(GGl$rxFfd0BMP$!D`Im_IsL#iN4e&4xICNNma=3fVzdXx0akb}J=xi%ub* z??5Y^PBlQ;M@VO0uV|$Gl`d%HB7Jh~V&PGT0ag%FkH=9lh;qT8zW{lfrqhr*b~zs- z5-3Jml9U9SrB6;$kZ?Mkj5>n$=YC2mx@aL6sYC-BEW?yl5z?^_b4}Y?mYDns#}ztj z_&TfPMvVl^-a$DU3E!wMhWB5?9atqzKrRj$h&b%_kUD~kp+H#Yp(6@myWO?~!I3Hu z=Fs5?L&$Ek1=NvFHk)oKyp$u6@HJeA0)gu%65GN}d$-s()mK`n1iAvzJBEpt;U*Lc zp;rPv-<A4eq!>gQ2X<i-UHB{(%b7ZoaEZkr8pXlNh({e^(G{YSM(iRIu-Pm=I9ra~ vF;TQX(RmkF9*^hhiNtoF^RIlF|7m^$H0#Fus?kFU00000NkvXXu0mjfhwW63 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png b/web/pgadmin/misc/static/explain/img/ex_foreign_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..acba49c4fbfd9b871444c9e8d528deda3a37dda4 GIT binary patch literal 1607 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 FV1m**ONRge literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_gather_motion.png b/web/pgadmin/misc/static/explain/img/ex_gather_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_group.png b/web/pgadmin/misc/static/explain/img/ex_group.png new file mode 100644 index 0000000000000000000000000000000000000000..8d5de31bc129a9abcf4a73e19a48739139f66271 GIT binary patch literal 1228 zcmV;-1T*`IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=(EA5f2CVejTwfiWOA0Fgt11U#9qOVHuUhw@a(tm>9z9h#qH&> z?c}iR<FN7S!|>?B?BK2I-mL1~tMBB$bEG!w=AY@{n&{q`?&h=R*_GtekmAse>DsC4 z<DBHxlHtsY>Di~^&Wz~SrlQAS@94Ab;k>5IWyh*@@aDkh)THLqqwL+ecBwj^wTIx! ziQdJ9-ou35!Gh+|q2I`d<<Fq3)@|IrfaJ}di@s3r=D_ROwzcJZ<IJAp%bvUMgW9`& zd$dE9%UpG!OlO!lj)kjcYthWj@w~q5zQ66y&+^gH^1{OI!^Q8@)brKV^vKBY$;t7` z%kkOT_1@n1*Vpyo;rG0~?5C;bsH*3`zwW@o?yaxsud(UH#qY<+@3pq;x47%Lx$Mi# z@y^cjz`^d+)bz*4@RF6$yGLoX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0)t6JK~zY`?UZR(+CUVB(*d`NQfXa6^~z!}1Oy^sF^V-vQ6PniB6gWpu~n<K z*4lmj>zxTpNrZFE={Y_9;C#4z;o;8n<_!#Ueg5^if#~TvJ0ZwowOV^nZ(o1^02;Vy zu?(WYUYl(Q4Gr7vw@^pKIx;e1MSTv3<2Jf8Iy!1WJp{L*;juA`9sTu|@d=i7GIzB* zcbx`ea%zfYVA|z!O*g08?e>7jJHz>4miG$*&>@5fk}cqxo11erraKf0N5CtJA`kxg zXjIZ8>{QT6K3YgD<|aru>;+DY$NeBgqlu&uVVO20Mv+K3EONld<MRSY3yFkmKo;vr z%VLRIaMZ#t5Q{)kmQw~~SwrptJzZxz;S5eXn_Jw|;E6=MKJf88zXAbCN~R#CDCt$u z5zCqTb(dHyv_vdKafVpTQ;S3*D}%DOp38&oS{ZE#LxT<JgH2|$1qIUUxtyxol6lbB z@+Vln5v*J&tfe8J%N0vHeP`xj-Nh5}&d_Jg`!|S1QnN@Ci&a%El?{n)noX>UfRE$& zSy&MSDF7*1R><$?^J*E&rLBr_%XS^%;`MqgXclXlMUhx+RjbvC5!ul?)~H8Yuxhbb zEkWfnGVy48hc@|gu%#mXatCCbFywBqAxIKQNmeuqm0E03i*lu6bQyolvg{M)DW<3E zG`wPq%cPn3+4J4qJzU%0fAJC@93H(o#>acL+6g{6I5>Tc4doBgcOSnwJ9~SM-(6h1 z|A0S!`uyc9{&xO-zlMMOJUluzB3ffiAkFe$9ch*S>MpJF|I(7_Iy;r$L}JbIn@VhR z$7Es@G5cI-#kS2oefq~wwp=~2>+`>z-(ue+J2o$;LI3~&C3HntbYx+4WjbSWWnpw> z05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppn qF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTX@`Go)g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash.png b/web/pgadmin/misc/static/explain/img/ex_hash.png new file mode 100644 index 0000000000000000000000000000000000000000..9f35c76538c3a41920a7b93b94bdf97443df7aa7 GIT binary patch literal 1169 zcmV;C1aA9@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001n zsbo@(8Fi+|Hi*HY#9nXB?oYw#V#exs&h4h&@<F}n38~^Nv*by<=84npY=q5bYthWj z@xa0E#>el?&hp;g_M^vPyuIzKtmw0}>eSTprp#qVzv+I_?y1pfi`DRv*YI-8?0nAc zpxg0|)b5kj@2}wVOTX!?)@^0T>qEQdP`>AE$LX%xagvqMa+aa8;C8`}HuUky@a(s= z<azV%$M5K~?&h-b>%{Eiu<YTk?BK2N=fUgdp10_I@9DMZ-I(RolH}8n>fNlm?Sban zmF(iL<I#@k+^W3rgyPSQ>Ds94;H~fF!0zF_pG#z^7Z=B>b%2f~b#^4RQ$FKkW936b z-9bUQ>wu4ZIPc`Y=+~#`)}`#;yM|jA(>_1o$cW#@hUV0yu-$XX5E0BgJmJiW-o%9F z(xSc&4#hh=;K_*H!-U<zg67eo%w1jR)~4*;x#rQL<<Oz)+qdxO!sgSY<j$b#*|yug zf7-fz<IJAizk%e<p5x1&-i$@K00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0!T?jK~zY`?UU<U5<wWn@pV8EQt5^jN;fSkZ!Z^txZea>#3ciXMG^ue5lb*` zBLBL(BnC@M_{lzaKFl*S`~03W=gh1~bf??Z7>o&i8z-E`2MDn+LnITE(kU`Ph=my< zli!=3;UOHsGB<N!4<_g`tKc-t-v&Vskw|g>!NW(76$6NJ2r~EN>D;qx<f=ddDj?lC zzfvATB(nK=DOmtDJSQ(+N?*MuQ;UmBZ^#ftCYQ_Kk_phjJ0f{M{b7O3OfD}k^&$OP zSQlBxWkuL!wbR&Yce&O%`5J+BAl-Rq6m~(aPN&nN7W801!-mmlLX-KU#frjNP-nB* zbf^P6IMC>HI?ZTyx!j(ABM$Jw28;N7n`m*n{ee-CEij_l=W|)m<M#(C9G=C&reF~^ z#ik`>#q9t^g?o`5n$u2q89~HPuuHQD{TVq$evdr}9gW5IqV%<k!Qp^7d|{C&ZS{Bp z2@Eq#a=+Jwj-`OFxEFRI^_BMcgKP@sAf3+iBOq2Pl`555t<kJ}Ti5ID_PBQove_IR z2<Gz)Cew$9g+65OuP&+V_amCh=Zi_q93GcW`jBWYcl6^=7L(b`W$A2&nV)Qm)AC8> zY=p)*2{p#QmtU5UXB!g~#e{J`Q!Sk0S*=#954-)4+s{4^DqlQEV)eLGs$i|rXr2#4 zu8J*k#g<F0Rt+y2&1QQT(pzk$)oRr6yvav+SrQb(rKlFlofH>!thd|kzAU`IGSb`9 zXpM~`UY7p|xp@{|V|TiBT>>)4pzcQhBc}iW03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfr*~9W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..a2a4e9369fa78c6fa19bf5c7814f8a586aed5565 GIT binary patch literal 1571 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 VFfhuORjdF2002ovPDHLkV1kgxQ(pi8 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_hash_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..0051f996783873a4a27db4b971135e95cac8d744 GIT binary patch literal 1452 zcmY+CSx}P)6on&<ilC9wDWY}j1EW==VG&s^MyMc>VE_dIWsf2%OOQ>VP^3a>#ezbi zQ$WfpN-;oW2^b&=k^l*WB?JiB_w`TyKVY?Ov`?Km=bn3K?)P@ef&wq>vfO70gTZ$B z`}qW$(($7$%uVxaUUo4IW>yn~4)ryiwS?^8pZAsxthkhpJ|kUEnO0vS%3>*s%xPsS z2k<7yY&!WTdW3!iaT!ycQNDmlo}HT35l7XO3C;8jz~MlDOvDm~m7Oo7J-u?muxfr@ zpW4Z+8|Svr5=g76*J7xhadTK|9F-Zn1z?W=#EU?ha)Ykg7?VO|88jh>7B!m<YlhB+ z+ihIKOFme=tgB-K^{c?37$i!dE}kC8*Y^qZlX7DhJFTT%m|NeG{<NMuQHSGZ&NB!^ z;v%k3I!Km}R=5~+lUn8L%?)9nD0kB+*n|W|{W4?{z}f(LBJsvL7vc+yV)2Gr{Z1in zFoNuUS%J~8tXEIz)ik||2I-d8IN-v9etFrj#(`wAO|24dG_VI%MS2w#P*Oqdl0sB3 z7yho1^%ArX0Ocg0m;^P88U<b>@6$+o03~@7;%^vuMm@JJ<aWoNJuAayg^%p>Gmnsy zuG1*Xb4;BYgOU392vO(P&!Kp6@p=_SEyk&Y-2;lk%6vCay<jj&HE-0dOV0b0N7*Ii z>@A6~WuE;;C#7g56s?$SP%?QaR1+n-c`~kT8uNVa*2|@o?lo)=KN~N}8`2cd*w{>1 zTTgj<YDFZyg1O@D{UE}YyxV#N4ySl{7?kr`5m_T5X@ui?`P^!3EZxhC>gh@L@R+)G zO(PhQvf3nzE#>#mKw1u{SyOTb#j{N!#xvnegJKyEY1bgl8X%hmqzq8Kx;j$0LMUJl z<qK%_8X-v|7+3Q~)m)Q^fP}#wDqs)hYxrZTbs`|9t4#~%jZRFLv+$sL4Uo=)sui7h z#-L;~yHiyh($Tl5Qd2dzWCRC>z`VsQjOo~s>UR}uO21G3b~5>_sl;f1pL3yp6Y(*2 zTg|QPYVFdf4n2i1ryt-~R&&EyEH~GIaAZa|e{p<ldYm><(Ym$Sy#1kbWFdS!sl4#8 zg+-&46R)?p=v<IrxKAkB`h2<TL4-|Z@SI~R;xX*W)A-68l_8JKw;U~tw3<);5q%L& zO+WVhmV94&T?E^GFg?51+bpQUzhTmQhVhm~3Z0o+9h<ZCwR#@S#fJ;<<Zb)oT##J| z)~QSg4M#(dpu=3@PP3E!chc@*v$C?VU<{A|;Ea$C)Mvphc3Q&ID5^bSMg}7&YYEw! z+G=rs{cXF{PQvQnc;JJIsEn$r4gNJx`JpL<IafAY`AhBA`O0bGjYCz{Rlhy-wHk~D ztSrl;%8Mf2s{-cqz(t1-!B^mBiO9Ppot??{A(!2P0&-5fl5P>dx>DZULg*TK_Nrt5 z-2iOB@sKY=Jc0s3a*{6G2s_h?5P1!wrHzP^j*5=&P&pEke^pz|yOz9TpDUboGQjBx zMo!1otB@1eyV;Rc&(=*V+v==K^@N)awupf0xSm8APIR0a))g^~LD(V`iz%%B9lV<9 zNW9qx+^!S-`8sx=M=9LFn)pSWRENVZslD!B8wv}&N}w0~Q)Iq<_h*6eL%R>T<xbtB zHVKX_vJbiD$PIhPc3|ksSjnS-lh?8Q_gnrdZaWp#?-x#cg*}W&rboNyF#et@q1F6p z9T*>0alj*U0b~~`wx_Vx`_n~Y1o};*=weXmz#wPa!-WHU)K7MW;+k{KB^hrTOISzk zQem*}7uv?l*3EgQg4t*IhG!(iW+b}Drze^M=7@AaA{-nMNQY2Iq`R||yR-9g<Y{*# t(zVw9;QxR-DG5oKoc{o%+b7`Tw>#41KY&_u`GpC9`TGX?bfIFt{})E(L^%Ke literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except.png new file mode 100644 index 0000000000000000000000000000000000000000..76c546a4dadd7fdae310dafcec2ecdef9649d4c5 GIT binary patch literal 1377 zcmV-n1)lneP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006>P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZJydFPPaY zjqWG6vC4&kzm|uj!nL^a^ZV4*@~N!lj*;EL!|c+nY?{_9i1sFWzH5(?-O$nT?A*cg z?Z)orvhC!s?BcKR=fQ#6N$usa=Gm3y)|2GZkm}s3cd&fiz>e(VuH@B`<I<1f&W!2U zr|sXy;?RxZ&5Pj5iRaa&`u6Vc<G$$Fr{~tC?A^KS-n!+`q2$h=>)E#4zJS}je%iZz z<IA4fyMEfbeQRKz9{>OV0d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U00K`* zL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U6fJ!G0)j%qd?aZR z5fu}c7>rs-_lqPS2uKb<h(XgGuGEK33lp=Hw2Um1oV<df5)(cx$|@?VY7i|P>Kd9_ zOxilSdivP3!2P0PU|<N*L%<e9h$*WW0rh~yjKRJz!Ik=uLrmGoKm|mbnweWzTAAVs zOBC;`SVOd!+t}LKo8n3rs9GE#S{$96U0jLO;s(*;?&0a>jav({i+z0kltEhjT>}Dx zaQX!$jRpIKgaY-1nSww#aj8!^Gy>=})5xgkm{?PyQeSXrL>$l-)A)qMq-30aK}mc* zDRE%Gq^6~3Wa89<QYfipK|(A$CpRx2w-)50Po)5&rLZW!xCEzPP;Ds%YatL~kR)gf z39qtp6+&Uk08WDD=4PfK4Ju{j6{^H&F|VwwG&cpi3aCSkSS=P1TU3bB0n$=sQ*DYQ zQd3)3UtibI*wozI)Y6L8FP3fY?MPZWI=i}idV2f%Crq3;Y4Vh*m|7qK8ivp@ZTgHE zGiJ`3J!e`6kUM)8rXJI|^X4yD2)CuC6QpC&l-Udnb2@84dZu8w&2;gSrOTGXwbXV2 zb<9{X8N^;$3nC}CU}#yjdd=E(a4mJ+AT3RkK<xE(AaYU@hL*q$8#ir+YpL%6X=$Da zVsEJjkrSISv~1nBJ$na9TF^p_D2MG#-nDxVY2M$pci;X4qy_TsgNF_wv=9}Q2M(cV zAtJ$;mK->6poFAkiJr!&3jm~}-@X0I9(w=)03~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfh#BXQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_except_all.png new file mode 100644 index 0000000000000000000000000000000000000000..ba24ed16aeb0d93bd133902b0b2218e674f84528 GIT binary patch literal 1402 zcmV-=1%>*FP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006^P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YN)&~ znAt0h?kBgg%7uZymWQOmwYc*0`_$F)sjTIWk=?<=?9#1ln$|0b_9lA1YmbuM(9!Yi z+`;qh#_r~_?c}iR;;-=M!GYRI?d7rN*_GwiljPHo>fEY#uzcLWj_l&D<kgYm(vRZK zjOo~??cc`Y(2e2Ei{Q$M=hdb9_U`ZFzUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyHkc~n00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~ z0%b`=K~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4 zBxw;56%&^jj9OrRk(88VkYoTMLO_ZS1f)P}iPb`eEpWepZ2==#y2F+Fuz8<}Sz1O` zj!9lYQAwEzpB5EWRW)^p77h(fEo~+pT|IpRY+B&4uWD#$1kppl7I=sOZ7~Mw0g0J_ zePN0#^&zJ*6=OqH5N&2|VQFP;hAZ`<cwf~9qQ%12&fdWcSGqve;t0{=<m}?=Mx+*Z zh!zh|FK-{*T994r>*ucm(h}en7!-`tFNhEWf)M}EFrc1rGZ2VCmcb2F!XklAGmDCj ziH$QOD!+z=MaBbdF-u5HN>0J)7nH>3n;H-HOImtHW)@B@D20-0HYCJya`W;FaBD#> z`cw-cT8fGbN=kA11=W@^uoeO#21$Y@knk$6P$d+m4B#YaVPS3t(x6&iQK?3Z7K^H? zDho5PtAIMxiPd5Wu|<_A9Uv{$wl!u*BDHn(4Gr~;P0cMW&8=-%{bJSb(Sf9;v#YzO zx3{l<!o*3FCQq3<4O0swK*JF_rq7r;bLOnsbLLL(1ajxh#?)grZ~lUXi{Q4@c7b#( zo;rttVQyC~NY7LZx0x+jx@`FhxR$zZppKa<r-0b2>Oka_Rtznx*Q{N)9<HUn2c)HW zGKjsQ9z;%V#?TV9ant54a4ikJAT2GEK<upzAaYU*hL&yHcjW9ONefzt5#_L5DZBUV zCC&T0_w7G$khDPFbLjA4gchQr^59_<Ekq<3v(keH50;XYEYZ^#bpZet8{@o}32r3- z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f<D*lWB>pF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect.png new file mode 100644 index 0000000000000000000000000000000000000000..fb536b11b68fca6c2feda14a8011003678204d62 GIT binary patch literal 1389 zcmV-z1(N!SP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70006~P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j^61v!$C}WqXvLRA$F!xasnm>++;Mf(vbE^o;r8$9wesx6=F+awtZLlAj_u#Z z`u6U(vC4OVr-z4&!nL^a^ZV4*@~N!lj*;EL!|c+nZ0y{@kCNSe%Uhb(E6~yL^X<m& z=CbYNu<YWm@aMsZ_9pG+vF6#8<<^tr(~#=is&%M_sJt)i;;!V?k>k>j;?9ie*r$Ha zR+!l<;?RxZ&5Pj5iRaa&h3hnp?kDf#zUbJe=hmg{-MQ@Ey5-QJ<j$Y#*|yxifZM!& z+Pi(@%bwc1e%iWyg@M18hosTq4gLTC00DGTPE!Ct=GbNc000SaNLh0L002k;002k; zM#*bF0006~Nkl<ZNXKJfAR90;fdC^ZT9}wwSlQT_NYcW=$;Hh>nikS+;RXAJmlQ30 z`~reP!h9rY5fK#=ml%v%NcW2*9|%YeK!`!p9j?@eO$!sVl(dX2lbpPQq7oB6Ey^k? zs%j7|9O@dHT1?tHx_bK9w7~tMVqjnh(L=x%M2IP?7y<Qw#EikdFu|4jkV8z_$Up@| zo0^$hSX!Cl3QH94t5`#{nA_Oe*_+}@7pPhsAX*%qoLyXr)Zzxw;_l(;<&9elvWtCu z{ggpk{9OYAgK+u<C5;99g@gk2gqeasIB}^@IWz+3G}Fka=$KejqEcUQXha;)7Ss5I z#H3`LenClmJ}Gfvzoe$6XJq2kf>J1{WI;kKJ0~|UAGa3dqEDp&qNT7XzqkaaUr=o+ z1#2M?Vvr<g3<<BYauq^h$^cG+=H_OmAPp*I<rS*LXfdy>tTZ<Ty9%g7jaV%f5L;A; z(gD&^Wm9d6BvMmbS6^S((Ad=6+|<&F)i0K9?(IlgIy$?$dwP2N`X@}BIBD{fshC<I z0UCzTF>N}KoH}FXtZ5xU#_SoGdQ9icoi~30+?JY7kdD?VGZ!wL)ma15GX=wKri&IY zS-K3arM3%1wk%%=1S@Jm?8z+{T2`)Fy=E<3OI<gJY+47>vc3+)p45b)C2+&WO`G9b z>U%(B^A?bnt@R-G#AXaF+qUn>-bs=cv=Af8VY`xd@7YV5_jm8xf8Zc#fxPF?;ll_m zL`CJn!zfx{3FgRAoC(IX<lw=BB_t(F^fX3Y007N*+;lfqX*B=<03~!qSaf7zbY(hY za%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0 vW_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfuI2JN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_intersect_all.png new file mode 100644 index 0000000000000000000000000000000000000000..0018157f64a5ae601a2db08fb1e4a553385c33b9 GIT binary patch literal 1417 zcmV;41$O$0P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700072P)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS6;005<^<VC*eOu*?=!s><8@RZo_dd}>F(d~=W?ycYR znY?&XjTw-(Y}n<?2dLr@tKu52<6Xt;am(yZzUErN=VZm`lGX2_#9oB3MRKDxdY-9j zkEX$oHuUky@a(tn?6&Xgw)5}DqQ_wB<elo{oax}2?&h<k%46^9w&~%U=--*=-Iwg+ zu&2#t@94AW-k9gxmgd-$?BK1JyLE=PNp`9`@$1Cw;I8Z5tncK%y3wPq+HrWUKHI&C zwV8gj<9YDr!0Fto>Ds91*Qf2@yLz!f>DsB_%ZlH~hu+17=Fy^!!Bgnhrr*Yf-ou35 z!Gh(_ptk3H=G3I!!h_tvf!n=*<jtPB>woLpxaH2E<IJAw*tWXvf_$_?yzqpU%w6l| zpX=qG@9DJi=+@xJn$W9g#g|0Kw56=6)Qphaadp(PwdmmC_V4Po^6bUt(yr00YTUq% z?cc`w_U^Z_%6EXLhlh*8wYc*0`_$F)sjTIWk=?<=?9#1l?A*bRlHGmFTbkA@(9!Yp z?Z)orvhC!s?BcKR=fQ~fChg_1=Gm3y)|2GZkm}s3b*P4@yf5tHuH@B`<I<1f&W!2U zr+&{?nAt1h(2e2Ei{Q$M=hdZ!>okq-C-39F=-8*{)}`#-x$NG$<<Ozz&Y$bqw%ope z+q{0-yM5!!p4z*9+PZy(fxniAqyuE0`2YX_0d!JMQvg8b*k%9#010qNS#tmY07w7; z07w8v$!k6U00L`CL_t(Y$75h18!$3~03#_{n3!2u+1Qy#(!#;X#mz&S7Se6u1^b1U z6fJ!G0)j%qd?aZR5fu}c7>rtAevy=vWRPS4Awock4+Nw@YKhfChAnWvfNcRISh~ZN z`mlMQiCJ1kR*p$tK~YJW37-}fRaG^0h!zeFO)YIE9bG+r18iF0v9D@qXavziz!rFj z0c|k`>H&$FfPG<#EA=6#F%@G&RS<1vZeeL<ZH6oLp?F`_2BO8n*3RC+3|G29)#3=z z;^ge&>PDm%cZe1bPcLsD+**)b?Ca;R0@4!T78n$a(=Uh+1A-9$&@iB$a5E5yK$gJ` zRKg;GPBV*&j){#kBPzd!ghj>!Z81woOiE6{=@*p5=bIW2_DfoNMrIaHEhvSOYBnUq za&q(X3vg>eF8WjpAzF%x3rb3H`UTaNGO!i`AqGi;CXnzduTUivrVQXDXklS)2GXEf zUQww=j24TkswxXJu&aPN)QQz%39&_$C><az)wVTeNFud$^$iX6jZMuhEzPZMSp8zv z?$LpyrL(KMr?<DSf5OB`lO|7@It^0`BtXLvI;PJ6lGA3+nmxS}$e1$|Q;*r)dGi-6 zgxgZv1=7(rb=IOqv%6|RdZuEy&1~_KrOTGXwbXTk$kr8$fM8`Eh&`nhL(8hwYu2uV zYpL%6k<IHtS~k>!*pr(vv;=M3w0R3$OG7V+Y}pFZvaJEcp45V&W&4huIlD;Gf)-*# zIc#^zp1u39dcPZ&_xJ2SaPSamfxP$dks}B#L`CJHBPd#63FhcAoC(IP^w6P0r6eUw z^fX3Y000U{;7!~3Lt6j<03~!qSaf7zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4Fh zG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bN XH99ab%9mBF00000NkvXXu0mjfCZzUl literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png b/web/pgadmin/misc/static/explain/img/ex_hash_setop_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..3a78fa6a1d35d8b2666ee3ffa5583db9662a67e4 GIT binary patch literal 1490 zcmV;@1ugoCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70007fP)t-s0001q zx!X2~!Eep(O~C14#_M*??55uGK)mS^tKuxP<Vd{ciPP?6mC$Bu(ag>9z`^du$M4O~ z^4{L|yuIwJtmw0}>b$+})YS8(sN_Yy=}f@sQ^M+n)bNzp@OsYdgVF7a)b6d{^O?MO zQjHmqwrtqt%Ll095Ub)EuH#+B>v7BMPQK<^!RKVf=#tg%p~PN<utjpCHF}<@YLBMD zk2du2$?)vA@a(ql>$dan$D+qz>g1j3<DBW>n(pSaq{?IO>bB|Oo9N$}=iQg=<FKdA zX7A{;=-!y;+m`0ol<eTGm%DX_wn=uXJMrtp?BK5J-mLHBzq-+*uG(>Uu0GqniM5%2 zwBvd3=D_LPs_ELO=+~$1-@AITLFwA5;LD2N$cNs=h33(sjloms*QVdbhTg-3-NAz8 z&!D#FeCE`o-NJ+1z=7Mnf8@=cx$A%H+qmV<pySM*>e#lr?t*-@L%i^Wmdsu2=AY~3 zp6}_j_U_>5)wA5djnuJo)yKTSzu&2=<&>D;#mDaG==ksIwesx6?A^lL!H?z8tMcd6 z`}p$9v%Rr~oVtpQ(zUVm_Wa-A^}oUFs;%YG((&EGk@4lw_t?(XP%76v4Bcit{POSI z-Sn%j=JV~w?&h-X<go1Gukh!=<GQ)mQY+$cP1;Eu-)lwf<+0}3mF3ox<kOJq+^Wd6 z(8ivy+*T~?;;!V?k>k>j;?9ie*r(rPJ=a7P;?RxZ&5Pj5iRaa&@3EfMdPDEyzUbJe z=hmg{-MRG3zUrWd?4*wR<=^byy5-QJ<j$Y#*|yxifZM!&+Pi(@%bwc1e%iWy%Ued< zo^8}&Lerv`vZEDM00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3Yd!z~0*y&T zK~zY`V_+Z~FfxGvBPm*#m|0la*qKPu!okVK%|n_N(rw`d`-PVjEqwd}f<nT4Bxw;5 z6%&^jj9N(dizFWiNDe@VLDL<s)Q3$A6SI`Gj4YF!yn><<6Fx1<Dk`dK5G@?)8k$;6 z+B&*=`q;F<{i0%EU<lDez!pS^DXSO(^?<~T!M-rTmHLoFOxegl1w@;gnOj&|nc@md z6z{88L$sLN*xK2f;z}2&S{xu+9G#q9T#3};2GQc~;pyd#TMM#_eSH0tL0bG>0|J9^ z`UNG81^b1B0`-KMf<QQNsZTjH0_Zf;$f)R;SW}`>UvOwd9MBfi_=LoyWSo9MNqjyj zabUlsrln_O;?#mtD5+#YLM%HcH!mNz7UZH&r2wL(uqeN{1gBq6Z7Bt7ArNAaBxno? zud;F#LSf1PPJ-s<W~LwwDrMyrs>En9udJ*zHwC*2s6&ldEfx@4REW|6(o$tpZHgpP zQ(ISGU)Rvs)ZE<E(u&nDmTm6sNLo5NySjUNdi(k(Oq@7r@|3BVS|9-$hR`u>Is?Ou znX`ak_8bO=x$`jfn9g6YaM5D8Ej67$9SlomEnT*J)~ppk=G-Y5ZZloEYW146a4of6 zAadP$28KBsX3YYzC%0f|*|=%*maT9tb=@GcX%djwHfuYGJ*f#pOW=;3yLQ91)c1hM z=7|gpduGkr3t~@f#?Z2F|AFj-7+MZ(n>FijJ$5Z<AqI2Uky*2jcGux>*s<i}Cr+Yy zzhyE|3qw~e4(}g7b^6R%v_Nj1GM9m2dS?xeKt6Hq{CR{HNK`URy)bLm#SR7>QF-<} ziWX>sxio9mWn2lywB+pBvn3=YOY}5GT>t<le%ij3CAg3P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f^-`z-2eap literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_only_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..7764b74f5e5e5af1a205b2ecee9ed184727e1fe0 GIT binary patch literal 498 zcmV<O0S*3%P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70001NP)t-s|NsAV zbaXa|!Dg1x!H+h2o~cd1>4~}9VaDrk&F*&1?7h9crNQLey@{>X>89TD^V}-D-R=M0 zDZt<E!r<=3;qS-e@W|uv%H#0M<nj6DU(Mz6|K?xO=kn9&^VI3|*6H>3>xcgAhT-q` z!N@d;00001bW%=J06^y0W&i*H32;bRa{vGf6951U69E94oEQKA0Ut?3K~zY`?bO>2 zf-npQ;7O;V0?Nb_&J(=<J35L^UDqjzCdSySWyu#<`)@-0>*s42VGTQwXf%l9@iclL zNdOXeuiySypCM4!;O@y&X{wSOIUXq~XQs-}6QvYS4hKrA@L4=0l~^f9_IpA^Zz9B` z$BhkkJMf8s@sL*VhLWpb4Q#i-2+rIQ+9-eP?noQ0lYBNH*ld8!i7ZVDly=E_-I=Ub z0iwNRxdislWu;A#vn&>!J9Z<@Ox#J(okv2`=*=e-1+Z!K=krEr8ku~;d=B=YX>j2X z3`^5Z>~y=h^w%!z!<XmH<A-BxricT_g}zMDF0MB}&$8Uyetc9c(E*Y`k!1ybMZHLj oF&RsOM{v$!pYbjo``5SC8S!5pi4Z+;&j0`b07*qoM6N<$g5#I=_5c6? literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_index_scan.png b/web/pgadmin/misc/static/explain/img/ex_index_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..d44eff429fa9a3409776ea88a11421582f6f4598 GIT binary patch literal 1298 zcmV+t1?~EYP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001q zx!X2~!Eep(M7`;C&hL59?^VL-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUOPl=ya2odY-AJ!Q^I^(ZP>4@#=@|<6!gf$nfm8 z@9DMj?Zxiqv+?W1?BlTT>B8af_vhLx>g1j3<DBW>n(yed=-!#<+?Va;vF6#7<<^tz z;H}o__3YxW=GvC*;jZM>lI!2C?dG!U-mLKEz|`sV%c5A@y@~4Gs_*2!)9CZ$)RE)T zkK)jc>DsB$=kny!kmAma@8e(T+p6Kris{*?_Uni3;k?b|^7G_h=+~#{*QV{@yYAa6 z^V}-n$%)^{h~LMD=G3Ii<nj6DU*5)s%H#0o)urasqsZg%{_KYD<-qLSy2s=2#o_P& z=3ngIy5`cN=Fy_&(V^_zxc}ZM-o%96!-L$xg5}Vm+`fRq;O^wkpX=JUz~AoV&7SJn zw!Gc#+Pi+^%$}{*>Ep|u5BdaA00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0?A24K~zY`?UdPD5>Xh3ZKAN;Q_C#*KwubLStTT}1_fLIkws7h8A(MzWmN>> zU-!(C!g1n>o1QNGE)F-m&yV-_9Zp~0%lzwkMX>Y7Qw$+qOC*vv#9OIU+E4Vqdp|Hp z3=Rzsj}RlHV`Co(QA9F6K0ZNAOioUIBtA_|O$`u3pQX}aVsv_XV2tRNGV%8*U%21Q zpI@J!9p9ai$!5?8$Q25O9A=eD<t)sqR4O&7Ns`onhN37fbRe?1IT?#6=I7@Xpj=p3 zRDo(~X=xcqonCJM%4js1F=S<>16kw|9SNjfucyFbG<8Q*i!8FN(;>v5|7N7XYFb^j zi6er`Z;S7og+&Wmv(4_nkhL`y`2p<k=g;S-7$T&omq}6$8iRq-fYxd@JHSEHv=d8N zUvG1Hvaqlg8+M>wZnp<RHaFW4Qm5mKHCn;Ey0JwA?RIZ>L3V^<DXv)CmdizhcYE9C z7f0lZot<3~3#Z5L4`9gNUeAs32*`uMAWESuRxLPecC-tp*W+<QAQTEmL{lKRzaI@^ z7CvMViX9xrG34k-K%&tED%OOq2kmmXz2Ncrd?5%Q942w(_?SncEW#FR7mD@!VzDr! zlF1~4AtxssvYSXG(yRsji?awIi*PCekvPMgV#wK9&yAg*b1CUWCX;4&;YGXf`$GYU zq~h@lIL+qrmmrE{uCA^!xWzRCxk9m6>W1*wBNU4rq#&NWE@UBJES7PkQfWgTi$%L& zt_y`cl#1nYRUAoYSeFiqTrPhDH>GOz219Oddv1(Jgp@!yg?4elFxgYMER{+qrCO`q zwWpwmuU=;#Kf#5+9!!C=D6<x|Mx$}xj>y*P&1N0_`voL*$X<^uSL_qg>P)FLo0X@O zINC)Pazz%YmdlMA+~Wvh&>fq3bh%)%n8jVI)w=6!OnAn7Y3ybGuXzBr6b33x=w6}# z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f@j>KSpWb4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_insert.png b/web/pgadmin/misc/static/explain/img/ex_insert.png new file mode 100644 index 0000000000000000000000000000000000000000..862d837277c99e17d2b66232de79fce010752e7c GIT binary patch literal 1065 zcmV+^1lIeBP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003yP)t-sBmgK| zTU$1W!3nA2a+aZzl9IuXHmaF8ou4@}wdHlD$3eX4%c58k;}QztMoPfx$EtN*#Oh<l z>TAd7XvplT#d&Va>__Y%vc!A9!GLwm?AyJ6+r5e0zJT1nfP2yJ+`)o`(eB;DgM`!Y z-o%97#f9F+hK$ti-^YjF$cT~E?%>IZ;mnGc+417ejN;IZ<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp;FQ>)N;I-kIv%s_fjj>EN2{-mL81y6fMq?B2TU;H~Q8obBJc?BTBM;JfPNo$TVT z?cu!a<FM`JvG3%*?dG!X=CkkR!0_h4@94Ad>9z3a!tm+B@a(qn>%{Wy#q;gP^YF+M z!Lnrl0004WQchC<K<3zH00009a7bBm000XU000XU0RWnu7ytkQhe<?1R7l6|m0NSt zP!vXK&`lBB2CJaOTA)a|q(Gri2tkO1TjWv@3IQV^xBmZM;7QKm5)32GIHM2U59@)+ zO7{1iGlRkKH2+{;P|ED2o<i9y7RwoRabmSzQkSo7wrlG8!sWW5Zmt4>Pn51=F&d2) z>IBhBy)v84HtG!NF6!#^)E1!r(pR3TJMW~P0*}+_^l{1Ycsz%>EXy;PNs=@H{0soS zsZ1XpT4Ta-wOSp4TqzX#AZ4@ZCSYUngQhh~OI2D}smLG~3Iz$e+4NHRx>yYJuvW$` z^<kBxN(CwX!so06?Q|;DAWA+@Hy5zZqVB&+@l8$9oxr5os0~RL2mO(muAG;k%==v= z?{&03tR0w-WO+_F>-VJ@Oxn%n5Qd^C4wf(0IAs5IimsC4t_ET>94@Z+-*8Z+6;vrE zDmL4OX6o)%1Th>A6*p>99W@-O6jM@*ZQMqqB9uZQMgW7>p*i#m+5guRgQ6hxVDr$y zp&Tmg*VxiQ7K(#Tq1&Di4jVOe7K2i;IDj6{=Q^OhkHF`j9~j8~+7t{*!3X_54z}(v zzyVU)=`^|+m|`><E<urD7#?zdpLbg!qEcy%5Em;j!C($DUayzcSJ3|AcS0pa52eUu zI?&-*wyvxEL1XK$h+=6#I1mKB2b~PZ-9tT@h=0*v4DY{{!oxzs?R3WU6?`!;`C!nW z0nY1jCn4^1p6^g_rK@7mS+E|rI}S1D`FTWN!TW1cBogs5lw*-d`L~U|Gby8??pJ!b z3_1msrXytzkCh?RRq(}7X*#mo?MOj9Ce&3jKILMl+*jeyDI_uXRqokjvW~fDmd(cA j94hm6lTUy1|Lgn&xg@`Em^A9100000NkvXXu0mjfS$;eB literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_join.png b/web/pgadmin/misc/static/explain/img/ex_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c391233c449bdc5a0d52d50f522bd3e35c649c36 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_7<@W^2*R&GEgz?Z3h8!ou#;)brTc^v=)n(b4kM)b!xs_i~n@ zTZg#3z3iu{=c=sduCM9E#_!9_@xH(9#m4Z~*7U)THuUky@a(t1!S2S#@6FEg-rn}> z=AWyq=(DuyyuIzz)bo;+(T1sHQjHmZrCYPXrlG`Mg|bG+s&$Tqt8$|?qQ_wH?6#)N zW$Wdh>g1j8>9p_bw(sb(^6bTgsA6`iJD#<NuG(>Uu0Heb#_r~_?d7rT;;-=M!L{Ui z=GvC!*OTPakm}s3d$U61)sf@UkK)gb>DZ@@!Bgwrtm4p);mwQS%8BRHr0(Lq=+~y~ z-MP8zf4c61<<X(!&Y$Yow(R4uyzqqFzJS}je%iWy<IA4v<DBW?o0iO7=--*_;H~M} zsqpE-@8-bX#f9C$g5=GfwL|Xa00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0r^QpK~zY`?UUJC(?Ar(V^BbpRmDM2l-2b%E>$$61+gq;DJ?Apx>_)8HEF30 z1qv<yI!QY65i<h=Jn+JOn3sINdveZqt{_~`MdpTR4te<yvEk;e#wM}(cFUc+BHuEx zwXMCQQ|!8T|3SCNw~VdAT=visCNG}~>Uq@L_ZU6tfBI|y*^ohN&5&~$8Xg&a{sO&x z)%W_19RZglNiNj$_TBprh!c_AZnuPnKYkkfd})N~g^7GY=8#tqWQ@OlJIjk*1$#W> zgqZ+yzW-as^djR)gE?nn@}vi!H!=L<1mfjN3{M>+(=)SYCw3BX`FwNp6fe$M7+;i6 zP0Ts|#ifABKyWz}Ug1&^<UqvyH3+S)tw$+doagEfL}HdoIG#wRD2Vfr7JgcU0O^g* zUkVLzoGXry#4@R@lB0NWs^H)F^p4ffmArN24^hdfs+Omy80GW&f-oN{gjc}IE4D=t zwfMKBQ@nt8X1hFR1{zO;+2q*P4r#JhD$x<&c6oOh3TyF16wJRei2A*N&O&C(yQ>A* zTTdh_V86<|uIp4UMlA~aa1gDeGGHqKGqL&y^4bu#%6@n+eE^xPqU7u<Y%fNWHY$*+ zR%<FRl1?Nyv!GOKHH{aECXMoeS}PV0|3jEwtnxul(+=~OPV9QFW{v><WVgBso0Wk8 z001R)MObuXVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000b zbVXQnWMOn=I&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qo IM6N<$f?exDGynhq literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_limit.png b/web/pgadmin/misc/static/explain/img/ex_limit.png new file mode 100644 index 0000000000000000000000000000000000000000..cc3efd59d70436349e5413f8c5d2673200cd74f0 GIT binary patch literal 1237 zcmV;`1S<Q9P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!Eep(M7`;C&hL59?^MF-hScz8$n0v#>~G5Jmf7)p&h3KH?WW%Hj@0gw*6*+3 z^985jO~L6KuH#$9>te_2IJf0czUNiI=UKt$YscuhV`Hfo7w~d&?QwDGaB$~uaOH1r z;cjl-ZEe|XY}0FNhN)yyjTym@HuUkx@a(tm>$dan$M5O1^X<m+?8WZpv+d@x?d7rY z>%{Ehuk7Kj?BK2N=)$7LVC&_c>f@a6>b2?Mn&;e?=i8R-<FMt|ljYTt>))-W%w_1_ zndaG*<kXSm(~#=js_*Et=-rs+*p%bakE+va@8-bo<iD=jaL1~3vEFs<<gn}Btm)gT z>Ds97;k~rudA8?#xaxo6&Wz#Ai|N>>x$A)A(2n5BiRjm+=hmj@)urv<yUl57?A^NN z(xc|lqU_wb-^hpG#)jt9q}{@U-NAz8(4pSMh1|e_-NS_2zJTP;pYP?s>)N;G)1&6m zq2$e;<IJAw*|yrdedEiX37wJX00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*pySK~zY`?UU_O5>XV!X``@E)R3}Nf|O*B$m)u`ByS4@xQIz9FPadbCWy#_ z5QxIR-d(t0;9^epp=NwO+}WKuzd83g&$%MegZ^zjB6tlvg%IMgSS)@*Je5c!L&VUt z=h9(fctj=}B}T`_$6pYFh*&O{i-`$^Lh+J#H90vcB}QJqnUWD>)6>#%;<hdmlBqj% znNi+NGuMdnZJ$&sm0G1%znh(%otvA}Xf*GU=I537>Y^pJA`vX;bh-upT-1Y}qNpWU zrdJHBuxd1!Er6>!B0rD_(XFkm>CkDl+JLg#?KIF1r;`Dr%kB06uIeHmuaQNo)k-16 z>!rcq^!bcncKg>^z*Rzst%U@<-VFmVK3~uTX8-!;P2>~V_R@9{;9VHHF1A>f4FRs| zBA?OE7vMGU#8sVnk=rDx1^uFp(!)}Krk7!LhhZ#WF?+&W5Q;>jF~C)w9^1QnUrFAD zodO!W2)fMJMPxr7PXMm!blKhehPqHzyFCE(hQql7Owi>vLwGZpj6gIVPo)7@b#KOh z^I4$5t~i`N223uuKMZVge?JO|R4R1<xT-gO?1Jfc5lbH&9`&dHC!2h8X_3C)(ET>K zCEkTm$i;CclRW{Uhm5oEtZyb+ez5U09OO<<^N=|!6gXkT=yIVYXK@xOl*Qp`v6z8u zp;Q`xnA|;C<PITUES_h9E0xL>VZ`DIvp*md{nbSlxu|lLN>vc~?IsI!LGL0Gf><J* zK7ylszIF^J7aUiGYNdX8C48}77w26U^+u!76h_)hp3ddaU~A`Rg$v-yWrSP~M%qh` zvMAR0EYM&p<#MBb8`9%~Yq_ZNF0Pu*=GEVt*n|Fa{RGa817HRj*Pj3Y03~!qSaf7z zbY(hYa%Ew3WdJfTF)%GLGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6W zZEs|0W_bWIFflMKFgYzSF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjf-+GHC literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_lock_rows.png b/web/pgadmin/misc/static/explain/img/ex_lock_rows.png new file mode 100644 index 0000000000000000000000000000000000000000..41c1148bb185c87898b3fddaa76be36a15703336 GIT binary patch literal 1520 zcmV<M1rPd(P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj700078P)t-s1prKL zYin<9ZE<dHb#ijIWKo23T)1UXxMxwgX;FK4c)Ds)x@%E3h{3vUQGR@Ux^Yo}etx`j zQG<Yhyme89f`YwxQHX|yzI;)Nh={*{QH+X;38~`0f>Di(jE;<qz=Tnbj*fDcp^%S{ zz=%=8h*6S~l9Q8@!H+hYm3+dEQI(aIm6n#4mzS5An8cD%#F$YswdI<go|~SYb*9Ih zp`pT_QO2H8o};6lq@>5AQ9-=u%c5Axr%}nMQA)t+%BxY=s7}hQQOB=S%&$?Wv9Zju zQmC`DUBv4BtpTdFwW_wZW5(*uwpDA#=xE67&bnBwy1LG~S+BgjZp-YjzP@$M?Ap72 zw8FyMy@}(!bKJgw|GhAK(eJjz#N5GxgwgKZ!-Is=@ZQ9P-o}QE)b8KMhu_GEk=5?t z$%*02ikI2(<IA4n&Wz*Cp5)D*;?Rxc&Yz&$@#E5u<<Ozz(~#!Tq2|$|<kXSo(xT+m zlIGK+<<^tt)THOtrLN%f=Gm0!*QV&#r{>z0>Dj2~+?VOvsp{Fb>D#L7+PCQ5nd;rD z?A*BN;F{~+tn%Ha?A^NS->vfAr|jOk^xmoL;H~Q8ob=zR?BTBM;JfPNo$TVT?cu!i z;i~N8u=L}t?d7rb<gf4KzU}6+?&h=a<-qpkvhe1>`Q@?i=(G0cv-an-@9DMq=d<wX z!uaU6@a(qs>bm&qxbf@6{pz;(?7H&p#rf^N`R>2@?#1))$p7!Z`SHN{@xlA?!~gNV z|MAlO^v(bC)c^F+|MtiK_R0VD+W+?3|M<<SyU{8D0004WQchC<K<3zH00009a7bBm z000XU000XU0RWnu7ytkRE=fc|R7l6|lj&CyQ5eRxeH+_N%WSus*<!m=*`Bu8B8iHI zC~mlcpojwm1gMN_hN04AG^HkyMp;_fzWiC;xpx#ij-Jk`bLxZdhi7KancsQe=eh3< z3Yw{ZPzMOMrc^$J5DEl>R3a-OF)@e8xgr!66UABC*%d@ZUSZ)af)^1)L_`RP1gMF` zrP$b5A(0C4Y$7i?Sy)K?L6_Y-qqanb<M+*I<|&mUcAZbVnRe~SO7sCn1_lO3#?<5S z41pnrVSK<x)3g_0A|~ZR%)0Q%xVS|K8R+b6_i*ZIY;5cUjNNMO2DH(rb8yJniyPR- z(tX=Gq#Ysc7_l>ev0AM(=rZcYkf@Xxj4t0ln?*eB=x3yTb~{A6t+$OdaO!GmS~0Te z24{TE!C>SC%|Gtq5pvPx1ztyMQx8I}?^v_?^qCXK;t$OVo);YybP}+Yfi!)xvdGo< zqo2Nf{PF$s@L+%cR@fzzEilx_FhjuC-A(&|*XeNdfF6pX+^Eatcca5>4G#A9K3UHq zNl8hW0WP{&7u8LGQYjQRgq(YWkWm(S7&eYDb~_H%=md_M>PiYw3PmYKPQCUc4?_J2 z3YJE}wpOZC6sRjLm0J*U{FNWMzhd0WWEXCm#o|Ip{0l#FH{`bxJN%qQMiFvnG3?@_ zyPRH5ds>^|S-9(LHaBpY&8802W$)8xFF$<!`R#4*z2@cx5W(|LbRmZ>%tZzHdW7tW z-nMaVSm>%{Axjp{p9>MEP6rnQE2UB?>VQoymz#m9AYY~jd{+!b+Qcai)*>$|G6923 zCL{R~I6w86Q`UtGx-c0!K!=_rTX>P90f}WyPLIC}Mb){v)4|$d(Cgbki&j(Bz&{wC zAMXHG=pvT{8mUC0=11^i1R{D_u2c)EBogry2#z!mA#<hDDxj8##Y%p}ZLyeL6TGx& zG*$JWUaeHt|Fy(iCIdVLtZgKzZ2=8xwHkI&mY3J^4~7>5D=9@T#H@>Qkw{d=j~MdV z#lWgX!TOOBenbyXLCdK|!XiqsSX2(mrbgOGEu0@~po`j)l9JkK5=)=%R?gJ_Sib;} WuicyymX%Qe0000<MNUMnLSTYGrAb2o literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_materialize.png b/web/pgadmin/misc/static/explain/img/ex_materialize.png new file mode 100644 index 0000000000000000000000000000000000000000..c3bd0bb90dd2ef1cc1baf7f932817d1b6bdf463b GIT binary patch literal 1221 zcmV;$1UmbPP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001^ zyUc^E$aSX2Hi*HV&EAa1-IK}Ps?y-H)ZnGh-mTK#zS!b$%<V(H=}o`rQ^M+n)bNzp z@OsYdhtuw@-}7s{*>k?y5Ub*3#pqna>5|p&pRKHao1$`-p~$a;;^52R-owF<HuUhw z@a(tV+qd1?w&2~u>*k;8<eu;8wd&)Y-PyJ2;hXR1v*6sp^6kaUy`#sfb>G{;;oZva z=CbkX#N5}k+|{$*+Q8@Bm*&}&?BlTA*tOf#vFYHN=--*_;H}=+zU0-B;M>TCsbo@( z8Sv)7tJG}W*1h1`$FJLRv*CB}=)&sVtLfaT?&7`L(XZLhuG!A5qQzgO%Ve<JbGPSw zxa)u8(U0QJjOp2^+S0Jx)VsRuf#J-G=+~#%%&gqgy5P!*=hmj**v0JKy4%va+tIk@ z)THLqqu0r)-^hpF#f9C$g67eo*vzZg%d6JMsM^oB<j$bnzJT7<!|U0$+RnGy&9~&u zp5x4(<IA4a#irW2ecQc%&=gc%00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0(?nCK~zY`?b6p*8bK5XU_ww#jGAI1rVXt0A|?yUN>Pg78bgs7LkqpPC|yAQ z^~}hc;|y@}z&Sa2@IKs^*>CRt?k<n_Q2(eN@lkOdJ9#WX#r69K{Ds9u;S&GJ)1~ES ze2fTIR@a`t5WIY~zW!Q(k;OL~8$t+$3(Evq6^TTff|a$mo9_g3PI><U71uHH@iqn5 z?;ilML?RJ$9V671R4U!#Iz}WinM{JZTtN`2QmK@pu2N4Wa``NxQfX!ot#$^{Xmr~+ z;j$<c`Wac&>g^qjd;+Mrj*-t4Dy|b#6bd*+Pt%5pDQfi=wPQ3IcZn=8g&xp*CKE$u z(db|b<Nm(cf)j<-YNY{fGTBI?)*T!gAu*fn1hHE8Xuz0kHU~)#4k59a%}#=dX_Ugi zI2^7!a^yZjWSnBxZnt~>x-s`LGP5^kU>L>)TrA6;0C@jxeL01O+O=3LUn!5*>+|C; z#@J8_HgFbX0nh#I{QUU%`{~6GH;+r<4TZxIl0>5{V9$cV*q<pEKhYGs)9Lh5zHmIA zz=<Oo2tX1{CR2Cu-AEu33i+r=Je|(qWSk-!OQo{J#ynmhOyN&tGP$|`u@jb!WkEKd zFJy^N>4`)VekxZimGCKCihQ|TE)WE!sAQ;OwN|U+B$oVjnFob(`Km#XM7mNfQuSJ` z*2GEb@)F)(xVoAknM$=<f~3_V2ujfg?M9=~CJ0PX&rzLbv)P$@W7$Fh-rw$adlOUY zb$Ea0x<A0Da4EXO;jl-LdJCoK-`v~`aMFOJ3wl#Xvo#uBQ-i4lK0K9-M)2V&WSpYi z>rG_o^ihh=U@(|_V-NMe)o+jt(ePu5AK?H103~!qSaf7zbY(hYa%Ew3WdJfTF)%GL zGA%GMR5CC+G&4FhG%GMQIxsLenI#?o001R)MObuXVRU6WZEs|0W_bWIFflMKFgYzS jF;p@$Iy5voFg7bNH99ab%9mBF00000NkvXXu0mjfVJ3t* literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge.png b/web/pgadmin/misc/static/explain/img/ex_merge.png new file mode 100644 index 0000000000000000000000000000000000000000..3fd8299fdcb72604d0c97816d38ee25ec51699ff GIT binary patch literal 1127 zcmV-t1ep7YP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001z zmC<Hv(ap~CyuIwd!0pk|^3&Aw$H?!;$neU_@!Q+=*4Opn;rFJf=Bcaa!NTsv#qYJY z>$$q@!^H2!#_)!zWKxY8p~PNwrpGpj!Eep(LA>Zn!0CI@?}XFvW5()e$n0**?3dZ` zpxg0;(e8}Y?vd5*uHf?tsp4J4>N2(Eb<ON+$LOQSVRDwC!H+ic@W}A&w(se*^X<m& z=CbYOvGMD~>g1j2;F{;$m*?A-?BlSe%w_81oao+}=Gm3(;;-o4nC97(<=2z!;H{?6 zXYAmv@aV$Fs&%W?Z0p~x>fEaD<-p_8kK@pe>DsAbl`meHCBewL<kgaJokg0;U3jiO zp0$U%?SbUekm1dYi>qviyiJ|ZV|uVayzqqY<iF|Ir|#mtzsI+$-f_6=fAHqO=+~#` z)}`&=yWz}=;K+#I$A{+Bq~67a=F_9#$%)>?h26u0=Fy_;-MZ$|qU_wb=Fy?$&!Owu zx7@#g+r59}&Y<1Fg5%7dI?;o_00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0v<_3K~zY`?bGX5(r_3DaGDn~EzQc+f-=ht?ef4F_ZT1uwF%R(Lb^=WWfKN0 zFq@$K>;1-ob697`-_$p~@OkmP`<&<Z{qD@+xE#k7!Wh%W5n^n7Vq%hTUY)u&O-wtT zGuH_$8NV?*J4f7{pT9LmOy0gTHS@oavu8O+V;7hOa^b9myh~n)+@p*!Z5*NQyWH*v z)WgL`OOL51%THIHQCQ;gcsy=ub#2Y{oLXL8e6fNj_O84fA+P%HH*FjNug~Z6f|sUg zKlm9Y5Ckmog+d`3=x{j9027HuW0vIgKO}AtmSrFiO(c>wNIZ@R!?LLW#1iZ2j3wDH zWf`OhpcKJmHj~4WH(-ouTamY;SNt@?_#qgJC3BGDIDQkbgke(=lwv)NQgHcvL9ilQ z8{6+3!+!vnR0I{9Os9(+@P&dk*?IrrBQj*kFsRrlDmGgz?(&F~%a-KR=PzHkNs=sy z$c&`egFQj0NLJ(<GT(ocN}?!|HXB1`XA4~s`&V+=4EGZ@c|njsl4WJz>dLS<v7aT= zPa%}c)e6WpRjr>w290sM`GP^JRT&hu(P*AR2H%Cx8^sD$O;e!W_|<CT$uNb2QXDjY zw-2$zW@Dx+l2DN)*ss@{2XOdD*N^ZIt7uwnm_qM#y2p4TYc*7Cv(-A$5$Se&c%rB( zDz@D^>F99WwM7OgbR)%4uh+w8IY(ocV>y2TWnrZACmaDB0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1n&OPyYY_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..7a9aa51fce9d775f169f70d115761e9817541c48 GIT binary patch literal 1599 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_append.png b/web/pgadmin/misc/static/explain/img/ex_merge_append.png new file mode 100644 index 0000000000000000000000000000000000000000..12fc55d76f504140935d5fa422f9a5075431bbc3 GIT binary patch literal 980 zcmV;_11tQAP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005JP)t-s00000 z003rd(Nc{WHi*FosNxW-;$)T3a-%gGuH(UvHg>8zdY-9xu0FMyetNM%gs???v_por zNkF{mMZW2fwrozm=1joprKsemspnI|>RQ3)jlolwyLFkoc&e=DiMiWd#p`6n=&rBn zp~POI$6%JsU2)6oq{?G&&F-hoW_r%-+rEF>y@|ZN?A*VB+`xgozwN%i?cKqGgVF8X z!h^rT?cT(M!ou!_)bQTLg~G${i`4Gl$A*&C@5RRNy3wP>#_+D%ag^Bb;mnHS&yCB> z@#M{(<j$YW&GF^VpySbw<<Fqw(vQy1^0ec5<kOJl(V^tjk>=8)<kgbV(emchr03M6 zw3*OTYfrLEud)710S)b!}rrs&tF=Gv9%*r(Rk^ttPQ>Dj2~+?VOvsp{Fb*xB^D z?t<yus_NXT=--*^+qmiAn!NCY>)x#C;hXH;y6fMq?B2TS;+*W@t?c2h>g1i+<;(2i zukGQy?BlQO<FM`Hu;AeL?&7`e<gxDKzU}3)?&h-Z<-hOd!0+g@@9DJg=)v&l!td&~ z@9Vbl>cjBtw(#t?^6bU)?Z)%($Mo^Z1Vq=200001bW%=J06^y0W&i*H32;bRa{vGf z6951U69E94oEQKA0kKI$K~zY`?UPkg!$1^;v)KUULUEU1#ogWAouV!7?ykih{xC_% z08P8uzzo9+=i$EWd~@#Ev&%65`jNspQS#J=aPdC=LHS%|Vph=rrxEdXaCDB~V*P?6 zOSoTiagtKVQ(H*3K0T*!kezPn9y(&R*|RBuD5{jL$;c}oWwnJQBj0x+hE!(ZG4|b2 z56J|uqU6ai*kJH@XNdN;E;@msASoyeeLdlI2K-Hg!O>Vfiyb6RLfk-<JSpwt1POuH z$A{Y&cse`Wy#}=#6BO#@!i&hmHd?uav*Et3WuQFNGM5Uyz`)%Gnzz7yUq|yS4PkhF ztFRheEux77*lcU89;dqKTir#MXUoaK4P4Akj_d*D?}vtngvyQCK3LpK>BaV2;4y5! zFcp^>3gRlIkf(HCo=X%&Q8JG`mtuU?vnWc&GXk+=|5<z>)+K-bO1R(MTt0_mbAQjO zbuYw{VGA{*NiY=`WVb62QpvD}s*xFtx!GwA)=08cuRN`gIaG!Ep))fzsaD}aS{Y79 zOvZIsXsWB7QXr(2iS{Zh6GdK`j1X5QioEi_{zPxhzn!H%4w>%&0000<MNUMnLSTYP CgEgxF literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_merge_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..6ce4839e02fd3f17b5fd8e358ff204046c38d26f GIT binary patch literal 1344 zcmY+CSx{347==TqEn;1Yb)kzRwvO5s8xTS1=pdpEBQS_s6{;)(R?#BJSj4Jq3RJBX zQDkYPh!_@AR0IrxkdTEC5=cT4vWF~}EH}AX?oB|$Ort*a;rwUL%=w=FQ<a$T<6{5M z{81>>;#h1<lGj7u%Fow(H%%9op-|{MiE#(_c;jQdE<1-e#<7zI!9lWxOtDPx9D+$F za|9Y;+1PBmM2g7e2w&iwoP>oUczW7R8US1I0KR>uy>o^_wbJQO_e)bxulW@b<ZvB4 zo@1B>(HS=8h)pa;>PUr2w*vp69j|&N3$LV{>k!lrt7&peF2@=_WK3t6FL1zCrK1;c zH7nuAD!5GzQ;lwx*-Zivior!Ux<t@i6v-ISq51BG4od>61lETNxJ+QH5ZZ2v>;w(c zr$;)~&Sx6uh{@f|NG-y(<=?}pne`Kl{^u_ZM7rq_Go5lf9JaG;VDH?l&W*_Qz^qE` z(rDcPFl)8GZeeAZfrp4=T%kmSLZ?ImE0ivyaqclYvz3#LAOEF|e_A$BCFnXQ9V7Dv z_73408`uMxdz=u{jY#L*+Na`NlkRVmw$Z4rw*oI<I~TTdU}((ckeqDT`iPf(toCb@ zT??6djMEJURo#rD7SwjRVJU3mIH578m5tcNm+*=8qsIyfJBhqUufSr+@WP;cFeAGU zOx1wur*5ajX&H5xSqLO*8Y-zE#x-)&i@KtYKUhz+mi9wsb~6oB6U@p^NJpMUrV*>q zZCA}es>*=`951s&nb&8&N(4(twsIRVWR$lXrFet*iAB}#cBo*>Bn%3iW`PS*7^Q7$ z_8+Q|3MKs-z-xxVNk~tFw8K^n)nS-0h+9>R>&oGB1*KF!-sCj%Aq~|!O|hzn95ds< zWQ&4YCLb!14P4c6a1JBSs-{>}Ll!034sgw~K0UWdJBBk&^&l3R0~ojKxv*KPW#gp8 z%b<J^8ZM=HN9j|LlyCqQ1x#go!@_geqvySjeW$&woSohR5F4}WAeMO|ZS{hWZ^o@H zjt<~cX=Bt;2A4)*(K*93HuL+nBQc3L{_3j4ufE$?-cl2G_hx4!iJHcXCZ>+~h4>dY zSFdYJuBo}Vk>A|xk3MZ$+vF3p@YH_cBwxfkBosto!jdAwL$+=?ya7+A@<*k6g(9w! zvR@G^meB8Yt<;>!+s)T3aowoc;8%FDtaxd7@E|tX<MBnKJ@e?Y(o*z}vfa_c)PZNG zs-i>z%K`%f)vG>Tv0{ZT@XO_&ueyC`AKI845G$^ZA*NQ}>28@ViTY+6jXxB0|Ihe+ zAGQbA9hF3-<mczxr>ZM7wVqPyI&zbynjb2^vgu!ZXGXE!his~s5{t;!8Lhxdd2+H$ z`a^M1P2{d350QAO=#A%f!-lxV@)Wji(}5@Phm(@(Lzd&2xj)T=+t1GfFXQUTsNU3- z3CFt&S^TUm*_%@dF`1P<NcVl;vpy!2^m&H9U6|t$5mLzMU;Ubr=F|HHSR3Eadqx5D zUS@KS_2<1=;NKL~a}pYy|H!jsP2}&ojk|&;3b$YI&{zkqJQ;7?@f+?)@T$!?Vu1u2 z6*|R)<?x~pmIY>P?D=^xPs_+6o5h4r&fZYnYKX{H+WIe;MNe~RudnS)#<~{;28H`~ zp;7y0eV6*_*%98?uP@khq#!fBAS?1jewNozp_mX%a7bt{Cgfl!CNgYGWLVg@n5~f* t%(lAqYyJnE&CNWOeepej+5QfA+m6J9zXwKZ4|RG0RP3IF7(#Sf>3<opDS-e0 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested.png b/web/pgadmin/misc/static/explain/img/ex_nested.png new file mode 100644 index 0000000000000000000000000000000000000000..15c47316d5d4163d97b95cda99b2e3a2049341c5 GIT binary patch literal 1108 zcmV-a1grarP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002N z!qAqP(SL){b9d2ZYtf>m<h8fzyT0th#P7ht?ZCnA!NTss!|uez@5RRN#>el+$nVI> z@W{&W%FFS~%<;_4^3Bfj&d%}9&+^dF^3v1u)YS9U)%4fb^{cMtuCeH+s^-7I?YX<_ zv9sxtmEUxE)|i{&!NTpPsL;d2(7e9v+1d5IzwF1wx2vUWos>nDi!Y6V8N<SK)!C8X z=A7p9r{wXW<M5#4@SfuCp5pDD;q08@?3>`~o8Rb}-shO$=$_f!mC@3Tzr1kL*o)26 zebU;8+TxSc+KR}^cFoU%&Cc<&uw0mqEU~Ov&d-F$$aBxniISDkwXlcC#=6<xjNRgy z+TW7e-jUhekLvTc$jR@iqGZ|JkFBog*xQf2zwOuBjJLS!xVh`s*o@`wtmEsW*yMoL z*Nf}&z3K0|)z^yM=aJRciPhDL-sP6m)QFdjE7;qU%*}nTs8!L=iO9rx!oF?G$b{0> zhS%DTytZrH;g{Fej@H)nL!K(600001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0t-n*K~zY`?bYj3+CUHha0E^Sm0C-!f`UTD2bF{cA89RMMd}k-_8X`@6D zMDcCwzpmmq!zFho^0nPBncU28_IB=WSEKnK57DI6=@B#ZI&Bj!nhh;RQ)^pWyU}cZ z)A6?RoyGFL>qB>s)oQibdVBlq-DU@7w9Wkk{RS54bh=CqZ4J>G20jkDS^IJi4ZF;` z8lrbO21iC&#g2{)nR@g!3&`nlGsS~(TRx#$;_)EO3xVtkGWPWA<#-<`!pC#oDzTG@ zm-7e4Cnl!^LHPV-`fD&4425UD%|;##g>e44==XU{gcqWVOA$^@mY1u)d>}fv62tcu zi?6P&^D2@+DDn7(31MX;iI<(+h;RM?6?qPr6k<u`VluY5#Uwyj-DZ&~GD!iwmYp3E zNvTN!?e11h8X!#~86`=e_H5Spl!p|M$tel4d9vA`ebie9IZ>Sj{rZg<Sws=27lu-c zC{alo_Vx${Bq~Y6em=jiHXz9~0tdl-K6I!$8ITL~EO2y0s0Io}dif9vlTN=_Vvz7L ziImF>GJZ_B{3m6ZPJE}8xcZ5m`Oke+!p|<Q#uX3w<m}?|il?`W$kJNndTTqC$=!&O zB+G?jsp7x9xaAm4DY72;gNf4L^Q&7%Q+ieFtE0i*;iR56euwqsx`u@l8x{?Wqy`3G z1LL)UA^xw%J#C$lG-cRqEC2uiC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$c zGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLe aHY+eSIxsNGmsP9)0000<MNUMnLSTY)!c1@g literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_anti_join.png new file mode 100644 index 0000000000000000000000000000000000000000..c1c0763337617f9ffe8cf13ba0f47f4cbc228c5e GIT binary patch literal 1741 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png b/web/pgadmin/misc/static/explain/img/ex_nested_loop_semi_join.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e8a17d409343ea937e43ebb76e8ebce3cbee49 GIT binary patch literal 1679 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 ZD=;-WFfhuORjdF2002ovPDHLkV1g+E(G&mx literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_recursive_union.png b/web/pgadmin/misc/static/explain/img/ex_recursive_union.png new file mode 100644 index 0000000000000000000000000000000000000000..66952ea454e3703dcb08251bd2273193aacaeb28 GIT binary patch literal 1224 zcmV;(1ULJMP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70005?P)t-s0001q zx!X2~!Eep(MZW1w!0A)M>V?$sl-Tfk&g_HH?Tggzt>5!Nyy*w1;t;Fi8m{AA#p`j) z>`uPsTEXXJ#psgN?_`zG-s;qsyLGzJqh@Q-%+2w=zwN)l?ZU(F)710W+4RoO^3l=q z)YSCg;P-*9LUN@xnY?(sz3iu{=c=sduCM9E#_!9_@xH(9!ou#w#_-nG^mC;*r_X10 zsycS7JFwk!QjHmRt30ycc6zZujKETQu|cJ%<dC*(*yYQi#9oB3MRKDxqQ_vQ%44U^ zW`?#&cB(tB+HrWUKD6U`wV8gwk2a0LQ}pr4@a(tn?6&Xfw)5}D^6bU!<+1JKu<YWm z@aVy|=X~nqo$BM9>EWC2=(Fb9mF3ry<kgbv-mJOnfA8zI>f)T}-<j^_vh3rp<kXSl z(vRufs(PNOy6%GS>9pzKn&{q{=iHa<<FM@Dt>n{?<I#@d&yDHXsC=|Tyzqqc?Z)lo zvGC}^@8-bj+^Xr?sp;6K?cuzZ%w5~PiSg>g@8!Sl;=SnCr{~qB=G3I@-MZ}IuH@B` z;?R!h*QVdchTg@6-NJ+A(V^?#t>e*;;mwQZ)TG|TgxtV^<<6ku&Wz#Air~qK=F+3x z!Ghesf!n@+<jtP$<G$?Py6fAx<<Fqx&Y$Ypwpcc+1poj50d!JMQvg8b*k%9#010qN zS#tmY07w7;07w8v$!k6U00Ih0L_t(Y$75g^1>^xnCJ=y<#A#t-W?^MxXX4=G;^tu@ zQVTC1zknc<kg$lT7_nMNw?!Q63n)p*ixQGjKvG&pR!&|)T2V<^MOB)R<&tXZ8bB?Y zTG~3g(t7#^hDOL*uzFF-*u+!=rxxs9)G#x*z@-Jd7o{w%tTk}?1-r1MjV;hGcG4gK zB^fj<EbJY?TCiG<EyOGw9i6~>aJZKN(>M(aXP_REv;f1z+0g=bbYa!PVBrGNg6c&y zE$GHsxMJD@@iq)#7-!*Tfnhl$q2L6P?j9KF2$E260x1tqFN|~qPAIs6hL^VmnqMFZ z1!u;P^700z3Ljq(fRfOJf-}iV`hlc<{R0Anf_+0m!@?tc(LxL(V^~CjT<see6&(}n z8yXj%km!r%atvE6lE7M$Q({uneADAIGPBUNWP^PHCBa&9z*=(i@(T)mi;7E1%h0u; zIvN;W<rQEpm1$Ll)xI^gb@dGhEf7DUI$Fb`yrL15lAFL`1tk&D3{C~8j<(1F>Hy^z z-{$b5#1`Myw)T!rge{O%fa+*?uJrBd&g`l4?d|KIFcHZw;8cL!(G0$mCYMfW^PM_v z!t@zPwt!Osc1JV#*3O(YyWMxr+<EgCAhbYI0d_|-_%5vPow~?(@sgzrmSKb#c1Po| z9FL>%0_={)uLY~4@dA8~9tHFV07F>Y9b_N@c>n+aC3HntbYx+4WjbSWWnpw>05UK! zFfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GK mIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTYtrHx7e literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png b/web/pgadmin/misc/static/explain/img/ex_redistribute_motion.png new file mode 100644 index 0000000000000000000000000000000000000000..06b72826862098966412a9ed9320ed4514fe3e5a GIT binary patch literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*@xBpA$Gw#oo0rjj7PU<QV=$!9G<yd-aT7Y4?= zUBXL%JkA1-$YLPv0mg18v+aNkK2I0N5Q)pl2@<T$oD2+%6Brne&c5vllu<2ljVMV; zEJ?LWE=mPb3`Pcq2D*kux(0?JMg~?U##SaK+6Jap1_l;0Rpn4L<mRVjrd2{T7+8We bfK*!<m_an0njX3asDZ)L)z4*}Q$iB}aV9cI literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_result.png b/web/pgadmin/misc/static/explain/img/ex_result.png new file mode 100644 index 0000000000000000000000000000000000000000..bfd7b5904f9b304709ac6aab37e24dcc06d233c7 GIT binary patch literal 1320 zcmV+@1=sqCP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002L z$<UU#(67SKeXh~4!_bAX(Osq0Zn@x(wb8-K&}gpOjmqed%IIXO*vQS$YP8;l)bMe> z<bu!aVX4@+#?YR;&}^sCf579B&FEmJ)}GYufxh8%tI?>y&|Rq4YRc_yz2s%c>~px_ zSfSIA(d>o8<yxZCm(uK6qSJ1{=25}wjkVEryyK13?q#joj?L+~#?YVI@LHwSTcFW` z#^!Uh-Idtykjm$8yW%;y=Uv3<cDmqo&Fy`{<dN0xWTeqv!RRu#=5@;IZp-X#u-cN- z?P09iK)mRBz~p+$>VwejipJ$*z2zga<UG3PRl(?g&g_)c?q;&xVZi4cujDnj=ViCx zTEpph#prd#=v=(zEVboDyXJq$=zz%RWX9`=(d|CD<!s68Q=QRq$?2xQ&}6XOaJJrj zx!-lf=SjZld&TESz2|<->y*ywR-w~O!0LI->S@2`Yq#KKzve-^=xegvb++DV$m?jj z<BZ7Wg3arCyWyqU@K3knEo+Lw00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0^dnQK~zY`?N#Yh+CUT!A%sLMsaGh-LM_OZl!8#apdwKLmBRyy7FwkURz=05 z^{DN?-f#qVLv*HJI{o0AVTQN6zxUqnUBR$t`S+s2aTTPh2@R$Ze@_Uhr6?^eX#=!w zkidu+dYpM2@p6b79vK~LYpmgw(Ik4&kDGzz5roD1dV(B&W5e4B`=q1wly#1~+^jML zcsL#Z*85J~R5W&<&+Tu6-BT{7A|X|P;{qx^*y6$v?}zk~X*x7LLn!g#XXoaFl0t_g zAIP46<ARx1fJ7H#9?<#k*9uEIb&ut;cg5uICm&DDQMi=5<os$BHaEGpPRal*X-K6r zalBmum3AqcgrAV>8=EE-ir5<7j^*+nDazi&@X2h!2ImzwkBpdc1Oj$;KNWK&&*v{K zHc_Fp2T>6_XL(<6MG=Sv0DC5#0-#mAvC+Nq*9v^kIK2l8vdFM%Et8knvxnJo1c6|c z&4c}KvKHW}Vy0H@L~i3sM*z8wP6~1|m|;789O!rkC-wRX3IT({=^1*&oHufd5<hTM z>Vx<$E{y1rNF{wq{1pVhD#p6C2Rn5oh%7L0oleB1N|4Fp`jMQ=#pw)z990@QuA5do z%zYPv$i2ZQ&zL%%$z6BtR(}-AOZ|1ZsiIV3#aX_aKKpI?Rtwj<S$$bw@^{6#TF;1K zr{3RVX9kpAD%Y_0MwLA*6vA-iVkfW3ieG7@w;>~pUC1Wk{1EpWn@(i<$E=y+6>NkK z&qpAySa4-uHvH^XzT03OH><a{o{ehAyMj8w$h-WttQ&NZpV96kV4My?L0ABbMGMDq z*$yScYY)=&)1fH`v<WoU-7VJ2U7}9J&`8I$z8yYm`gKnZK)LWFQpDw+wQo`T$%m=d zzQj%A4ia8s<V50kDpFI}g$%88-LN9{Um<<~F?K%Tp#n<Vv$^~qaIuPR*#L_H0A7VD z3nOkq=7|r|v-~&m2P92<JOAsn6#xJLC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@u zGB7$cGdeUhD=;-WFfcfoB_03(03~!qSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL< eG&DLeHY+eSIxsNGmsP9)0000<MNUMnLSTXtOrt>n literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_scan.png b/web/pgadmin/misc/static/explain/img/ex_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..396dfb4feabdd85e081bf8336304129058633c5c GIT binary patch literal 1320 zcmY+CX;4!K6or#E43U(&OiX7G0Tmtd5DXYmgR&F@acWZxiv&wwL>3hgrBoq~lr@it zLJ^duAZWq5fw&ZkC=h`X77>I3W&snjFJvdI(x|^WbI&<*@7(X#z04qTpskIa4Gade zJw!T4v82aGA-}XZR*;$vgTXU`4u=peEwhE|na4_cJ>&OMPHdC^GN?%#(geLygmo&i zN3_g;wJ~hf>0VV*pQ>a+SI*I098_lwt84kXyOa8Y(V1&wnnwbI)t>@VyL>~#^s#Q` z-ez%7n>4gTN@YnI!|M1RSrS`*eOyDod9RKoioG$+D)iJTAoVnDW}2o~Kn4Y*nFci? z(4d5jN=PdLbt2HDg!CeCRtX6-W+}%-_OSp37f^A587`pV0tPWSt}w|tfRYQSEfXG~ z<pD-9I3_n5EVvjnE1@|h#C^#el^bWp;E2qi;{kdeVBi5}F*q#M8+pK-7&KX20?sR; z1r;<X(GQCC^Ad1T#TXFlOnku12j=+L1qs+M(#`ULMG4q9t)1s%*%ntpODaaswDupN zW=R4rs~Ft^&Eh0>X%f3E0nHYQkNqG4U%j7Mp2U7oF*>GZTDYnYlh_prI4U=^O{(k1 z<RH8(z;Xk43WXdD^Oa1*TAEd7Nz|V$N&2LK-gs{q?2D;G2mL}wJ?au}Fvk}SCEl-Z zn!Q~=7IE=$y}e(yGh*kDXdI~~U{jVK(F*Yxuqnx~>1&_l=Y&sWTE`Nqyi*-+eA9Md zK3zI6YurED-VlgxD2VgQq4T)o<{Uc52dBM4_ns4qT@<Dvt#*S#&6df$?z_JA^7Nd& zsc>|3T=BIfA3pq|mf@Ygu#{_8Ub(bzb>X|nwg*!@UBbMkgoVpZr*Tf=$$yMQS7cHv zJl|yI9uG%_?<;ufhl(nz-b3s9yRngm7!eBB**@c+iOV>**WUgtxir4qH!Q58sBY^X z+t^lqCrqiOuN6j!FCm^Z-Pw}A4cEdyv#acY!)jFJxKh;d#_(duq1<!#u|_inUhRb7 zZuWs4?RmPM3Lb48C_72VNCv(-0Y~+p3u~M&y#z-hvq<OPO#~HPL|HeT-JBnDa|-Q? z%<Wv4nUHu7scz!F?nr$`t8(+1oBKW|Pe5|!z>mbS2==EN8$unCzu)=|NpXJS+8k(y zsf-o0Hs=vz(jedS7h1^)Nk6Egj#I}j#|fGRi^DszZaa6=0t<S~OgC$5;PxXZf91sE zOWU(6NzTED<doV?9Qs3{X(;P@)9MkAuHxQkhHpV(D8foPn!Wy&AP<pDsLJyP%3oh& z_cAYs?`!v|IYy!w<2r@-;@--2?03|0W>xir$OP}|H5oNdm)-MvQ!!rm(9c)!#r=_M zBHea|)}|e>!%!27`lYDuS>)H4O$vGq?bkY|V%O_yDBIEKFR-P%ozXV=^u|^833oyO zaZUL45Q3B6k&=}B<!$*W;*kcVXyLiC3y+ARgakaz>j~!U7+UU*(%Cey-DHB+7FHqH zPj|}S-*ndrRToh|R<X8I9r-f-LcEN{x??i2OZ4-b(JqNaSpSxvc22t`6N*Rz>U)~O z3XiIz)B{0V)^^ow^e^-{bxVdh`d7qN(nH;q3&j)u%b;lk?cGMHsP*lX<>$Ai5W`cV zkEg^CP9(=z0_K5p$GN(DxZ>PHJa7d3E&?9!g4<2N;r5nqb@(5Um=t{~HtjQj+xH3h axJ|%$eg^tVLmyfI*dZeMV8gextp5Q0yRj$$ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_seek.png b/web/pgadmin/misc/static/explain/img/ex_seek.png new file mode 100644 index 0000000000000000000000000000000000000000..130fbd8f53ff5c2c757c8173eb62a1b604555f34 GIT binary patch literal 1326 zcmV+}1=0G6P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0001W zrpGpj!EVazM7`;D&hC59?oYtzRl@0p)bM7=?3UT_g3;}!-tvyr?vmE;ui^6rr{No} z<6Fh+V#n(^x8-Zc=yH~!hN)yyjTym@HuUhw@a(tm>$dan$M5O1^6ka$=CkqY#O&j+ zp~PP6<(}%}obT$j>EN30=(FhFndjV>?d7rN*p%$xt?c5j<kgbw;jZi7t?lNr@aV$t z=D^3Qb@1lE>fEaD<G$n4kK)jc>Dj2{(~#oMjN#0S=-8+2;k;g#B*DnK#F|j0%w%+@ zIG(kKuGw+%>WA&)VD95x^XP-`;92wMfbif}@ZVJQ=6#RAQ?cH30002z+A8STDCyWG z>eeFb)Es@XL#xzmv*LH^)gSEB81mgwaGgbAl`r+=dg#}t=hUR^+_~n_qTtDi-^YgD z#D(V5q}{`W+`xk0$cWs(faK1gsoHLy(PX^vg!0`^^V>}K<977gNQ<j%pw(yY&=l^^ z5bw?o^V&-A%?rQBx1!f+zBxuV00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0_90WK~zY`?b6v(+E5e+U>k6&Tea1i1BihN$R<*($RcX1MKFRGK$JxVf+$KW zhy}F%>%F-wiB95-Go4N!ybt#&-#z)Ab9#DS&%Zx!2<}MUVuX;%<?>#luYX`*kQjU` zlMN9=eZ#{e#K`E_*gHa$$j8UW<wXC)#Ke2z!{p?ojOaytm>8X!l8q66sme$E&ysih zt7&qYC!kO&l?v`wDPTseR?osLMNt~iXti1mw7()hkpiNeo10UDQm51DL2WP?=7BPr zOlHtpEEel?M1_c&BSs1+lgXro1&hV@3{im|lX;^N5wpo;(ZZt5X0wYEg;J%O;ZuCZ zDHa^yu-ffQqT~y3NAec0qSvcYm3fLnRm^78CC#GM>VRdZ)43x4V<?4zPhsh%aJt-X zk2q25T8%Zf8@mWro6YM4r`x?MMbIodjcv`s?sd5kS@roO$Sh8w!6_Vq6e}Lj+B#1* zzIONK8}5wc-65M>-;p8xoPq5?Ah6xNgTWoxp=o*tc0-}?Ubo6-WNU*YN&h}F5MZKA z00PlyGyuU^EFJ{<;NXCUP$H2C^W-qHdF1!+CzB*1Q6`E>EC|7PJWeB$N`)YtNT)MA zA&*Z`6(sm7u~>_s_vus$y&p~s$r0`tnG|LTK25Qg$z)ESkQa5#FPw|RYPB!JQhOF_ z*>zaY<#Kt*vn-njQ6gLqkFQY3Lhh_sJO}ooRAReiUr6j;FJ6yTv>w?);W7ugV)23n zwp6+*OAwdK?L_bUd~1-sJUh$5dGP|1D*;IgiByVwxm@mMIr;J89XtMch<EH7&xM=C zF6@TGtyxq~;j~(<-oQ<*R=ep`xsCif<aX?uGe9#bCe)sFre3dCpxS6Q@1S;ne_!j6 z-?x#6<TXBM$LJK(U5`q=-l)P|v)QaYCdl9&YgGv`2__7gbiIy9qk#$c@nh0%Tq{c_ zMWvPEu9M<XmiBo`$6n9>cm4nf0rwvzb1L2d001R)MObuXVRU6WV{&C-bY%cCFflMK zF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr<GB7bPEigGP kFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f_kQ{fB*mh literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_setop.png b/web/pgadmin/misc/static/explain/img/ex_setop.png new file mode 100644 index 0000000000000000000000000000000000000000..f3a9b1983b5b47c96ae910e73ab4260ae9c28b73 GIT binary patch literal 1143 zcmV--1c>{IP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002E zxzL`V(1?rCc6!ljZ_&-ct;w>B#-wM%nNGrzJd>5te}mbYo#C;w>b<`0$jI=)!tS)S z>Yk$FfrZ(}s&>qySJ}LM<k6by-Kg#6v*XQ`qNLELspq@A?YOz?x47%Bu<78)j_l>D z>*J&8;hW6M%aoVjwzuoBvgxw3>bkq^zQOKonbT;Cw%F6E=-!y;+?VRzrRLP5*SC1B zujqQE*JQ2NWs|?=+Lq|snys$rs;uaQsoGkq)?dWwX2$7un78KHmFC!#<=2zt){@q> zb)U22NtVh}z2-Hy=1RThb;#&boz14Or{vX=<kXSo)|jNH<fy9WTeRLOv*bFs<#o5* zUyi-x(~#rRkKMwEAh6_t&FbUOj<dAt7_H;t&Wz#Ai>j^WVVTb!u;hfp;!=vh;meBO z#*ekO>Wt0lK!(EL%8BLApgM`e53A#l)9m2Mh~LPG-^YjE#f9R_n%=~P-olRE!h_qr zgxtV_;K!5Guy4}DpWelaCqTqQ00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0xn5JK~zY`?bK^i+CUTrVD7hwTp9u~3K&4efQ155Dpjm4f~c)k&`L{%-n1>) z8Vm%m{&hD%k|mfKr!(y*&NpUw=DfQ(dlZUEP3k|EQl-{twHmcbIry#98;mBC(V*AK z0c6TNZLwNy_D3iJkj{ZQUHHrlPB<~gy=WGlv$#E8ug7AuTIbPOJx2O`et#ek@cVEQ z(~p4#WO2zm9bC3Ac_=qPq43IMANT)2Boc{6p2Xsg1qngSR4_5mlTc_inS9EFXf&02 zhC3aSREyMFdQBwH*EcfBO%4E&da?EL)fS!|$)-f@i8MsEbNQXZ?%w{O1t(s=IdEa{ z9UyO)4`C8M+9{SY$0rd1ygNNTC_~YdQ=T+TwsVE|#Zvym-aY_BQK?j7P#cx`;~Y#@ z*NbPxQepRaGbMm(wdRV8r%``OjF8VqUpSKa`fZqr1GRJF!XOaM_w)$K<<I)$$4{|E z?Yv%V7zLtrAHsyXEd1ig#_vn9Mg5AVV<tJ`7D*pe`=HruLPQdb$`$xve5NY^u4%^j zfaCL-0Jv_EZNmdDS!~f_Sppgv`A=CNwrBy-V&I993`~e0m^z<{1x0q?S(Y2i<{%R% zy5-);Sjr4PEwt!%S>{IaFeOjS2A<dne{2A{WhN_mVq*{45?=X3(8Ek!_M&$)_K+p( zBEhYTPJ<wC!A;%vn9e=xqQ8_-b8vJi#oJ7y!L+k7OG)t;t8Y@1`X_Y<dEniZp!V7a z0000bbVXQnWMOn=I%9HWVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFU zC3HntbYx+4WjbwdWNBu305UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ov JPDHLkV1j^qN`L?W literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_sort.png b/web/pgadmin/misc/static/explain/img/ex_sort.png new file mode 100644 index 0000000000000000000000000000000000000000..1d46fd34beee098f997529bf0b7714c52232a2df GIT binary patch literal 1157 zcmY+Ce>l?#9LKkGD0JGb!<|bOQ+Me`PIBs@X131ubm*x$mvXaab;*yACb5J^<yUCU z=?G6fnfz!u<i}*hkYy7xW3|nXjiOR_@wspHSATpy@8|t_KCjR7c|Ol4eIL!oZ1p#* zQ7Dudg-rBA)cHdg8z6b}L>w1|LZ92`8{m!DQ{|nmX`=An**#5DzO7UKZPUMtXP6Il z5fWW|pN=clXUJv+$_1mFs&#^Aj(62w4Qg7mCQzhhh$nO8bCLPQz+!<`3u9yCLG%bb z?15U4$&kq)mBQ#~6BITAuO9LqLIsSB)IkpP_6i{rRI10&2s?LDwdh7Z8fJ@NCJm;! zFd4t3ITfD?Q+k-tfKm+#6{x2Ho*jVkUqDF&&9OlR$ex0982Sc5B7<QifWi&bjP3!r zaEsx0$?8cB`nK#iITTstVily{c^X+e5er>i<q%g4k%ho6fRJ1W5&*YE99$-0RE<W} zX*u<}b08K&QxnwJgHU)0{BOZo5Q%sYYAS}-7f?P0MUzmdg?qD*qJqS6;3y$x4DvM) zseqCx$W=qd3>dXTM?bXpLR$}rBv8e3)XBr99y8x4qpF)h&;TP34lIsGOB-m{TFz%8 zmqJJT(fm=Knjt1)R-Gi%qYx#33{uyzT`1HF4+_yMfZVAcm^py)vTU8m)18%`sKnhj z*<uksYUi1eVOfJKPs>_|AHuUzvW>}&>XtFnD#12=5jSD-l}O2Xy6AEAsv_w~<-a~= zR<a9*e9KC+;FgGmLH*CMbBgT*1FGqRFG(blkIk<5_s=(bzrrV0ONLT{JvvNXj&wR) z>7XZDI#BoKl9GL|_MWroq;CqTDQRU3U&c7L*{b^OT#I7a=4*Z|__`WB7ft(h<#lmL zwVU<juuHW=)EJqm7n3feC-+#%HCxw=uD|m{yYOyl`E(|KL();vVdHgcQY}`jeA$Kz zd^GU|aTDfZM~Hc9Sy{U?g_H0ClY?C)4vFx^B<8H|$3?8%P+fzuPdEAthoRteGj^qv zp2y-%Cb5#6EEi(d{<;x1@Ul9Xj(^`H-CwfeY>d+eFuzNvy3((g8#?Rm4)+uXRZ{0S zek&Lj2&|vqTX>h8z4p+Yu5=*Wb*%X-%fX;6ZCeB97F{VJdvHeYIL!geO(qzY#fd~4 zgP|L%u1gYzNTmVY-#^*ix*}V#)w7h0IfJh~v<cg-uAtgBZSQdJ-+WSx^D$TOOB4TV z&ougHZ<*gtEH4SK60NlsIlMIuW@DxNaj!)u>tp7<>2HN#d3gq@q^0Jug@L!_)33u3 zSD40j=<&?;yenlDmRu9KMFjKSyr<uxY0vOCm{D>(4e9y6VRvwCmgKfwx9qwK@bjUR zis9q0OCHVF-XIovFSc|R*2(*Lx0j!tMXN^#U$e&f2a$)ekM=$o%{USr>i$P$C?Y6l zf)l~f$=Q+M6yQv7ciHCd;_?IGCwBtDjc339GvLo~Mi}$-CxEcyBk-Zyo#6Tj=q}h_ PfdD9qH;q`i`*8CAb@5|F literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_subplan.png b/web/pgadmin/misc/static/explain/img/ex_subplan.png new file mode 100644 index 0000000000000000000000000000000000000000..e13d7794e91fc0842702b0b34c1a9b61607dcf92 GIT binary patch literal 1283 zcmV+e1^oJnP)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002O z!_bzQ(SL){ba>NdYtf>m<hHo#y}#_l#qYwz?#9UP$jI=?%J9p~@y*Wi&(QMG(el&N z^Viq)tgh&<vFNF*=D4}*zQ66j!R@lN>5`V;n496cyz8c@(AnDc$Hlj+rEHy)MVE~( zje!}GmC?n;b=BCB+u@bv?y2JJpyBGA(b0>*y>Y_8Zq(O`&Cz|**oW5HjmgV)&CP_q zyl}CsSnBe)wXlcC#=6+uj;W$#*yDlM;eY7uxXQ|X(bI*zwrqx}WKxY8b*9HQh{34O zXl={vL%r!uzvx%P>V?$sl-Tfk&g_TN?ycYR5Ub*n)$gj(YI2sLtk-VAk2du2$?)v9 z@9DJj?Z)lovFzcl@ae+p;+*H(mgLov>)x!v$huvZB(B<V=--*+(T?ies-Crnc&$CS z>3-?jshY`Moz7yq?t<^;!0Fhh?&7_NyG?JLL&vIhi>qwE$G7O#rsmV5>)g5C#f9C% zgW=4J+`xh5&Y;`Af8@=c4PV1400001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0=h{=K~zY`&6Md=+CUh_IT8h`QXz`eqXw2kLy;n)g4XJmdbG8avTB3Kp(v<$ z)p}e1_3p-?5Zu7nnNFV%o0)f?-@M1}Mx*)X((3dKs}!TxX;p}pR)f)GG8$jBwRd!w z%`ZDUEmpIMqcggeuI?_I0%_~9**P5z(YJQL>Qz?8^x17DJq=;{x!wU~4cdV|%WIZ~ zu$^Xx5QDtK35c8yeo&)jELJMwVp*3&xINyX;bB4W`rcrMwbBt;yniI{)+-1?FfbY# z<5dwki^CHb36sj4;gCDzP(xg7TRUOE_;`3?5(g$H!Vxb}L0qhf<BXVz0ua3qO*$hH zHH5VoIL=<X3)B(ZiOt5=WWh)fsJ71<dhlKp3=LHn5NrmCg5jxYL1vmmz_>6q?R^LC z+aGBz3y6${r7U>JZlAM>UNjEhXh=TF8Nd2bRuFzH;GTIO2?j%Mzk8N%fEdW$AV22w zL@?s<g=QOEOV-}=<mI>0-wW-D+06_Mp*`e&BlRIa<9G3lpVBjaeSfJrI7i?75F?V; zhba6A>5ka^!s61W*yk_H%U@$pB6W_~LOdQ{ip?)B&3~&x5><%OLCKO($?{#QQC=UB z<Ren&Kr5@OYb)r7D5loYlSrKdt)|oIH6(6iGFem^Z!W)?&s9dPbVz|M5s8^hVH*(_ zo>gwAm@Mw(G_XV%g#!oHwzf7zl+6?hyND182=m3g{rzGd!crMCwGM*d8pU;Vu)TYD zgz$MJ63OJ|-to!teyLO{m&;J$!1{@Z<P~R0Bq4++r@u~5@V88|)H+C(^;9Z*fR4`2 z&M%~1s%8btQZKa*97stu9$sEvoj**h=5i_>8k8**uFuf<<<-sY<GEC;&VjbCuSwwQ z=Jy>1Q997kA*u1=_V(_Af+!tz^Qco}$N!-}nbr1E9_U2o0000bbVXQnWMOn=I%9HW zVRU5xGB7bPEip1JFfmjzFgi3dIy5vZFf}?bFgTed9smFUC3HntbYx+4WjbwdWNBu3 t05UK!FfA}SEif@uGBY|fG&(RgD=;-WFfhuORjdF2002ovPDHLkV1oA>oooOA literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_tid_scan.png b/web/pgadmin/misc/static/explain/img/ex_tid_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..0a6063a1af031c626802911fdca598983aff7d52 GIT binary patch literal 1074 zcmV-21kL-2P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002d z;PI2T-@Mf8{{H{L*6o?Q;ibal>hbyT^!nN5^vBrl+3WSI#^#K%-OAhV<Lvi^t=n~> z)~3be%jEIR<?+4P?Qx#e)#LN7$>)Ek+0f?l*6Q@d;qbxV@5$rvYnjrc!{ox+?t7-# zwb1FX%;=%P<Hg|a#oq4t`u(HD<awmm>Ezqh$F9h;kiMjKx|(3PkxRstJB*5mfq{XC zhlh@ij+T~|prD|vtgO7eyv@zc+}zyo@bKZ`;laPVtDlO=oI}p1PuR6w-oa?$%4zD; zYVFo~;L^J5>E!0-=GocV($dn%$jHFJz_hfqs;a7)nVF-bqn?|W>)wU&>3;X;Y4PG! z_2EYK-Z;soXy4!8*4Eb0(9p`t%EiUS?d|R1)xgxbiOHZ?)2mYZ=33Can9k15#>U3O z!^66|x{;BQ>gwv<&a=<QxxT)>xVX5tx3}Kg*UYkn%e$bxy}jh*<eZ$G=;-L1o13t( zu%DlwudlDArKN?1g_M+(;^{T(00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0qIFZK~zY`?UY$l+E5sVm1q!Z0s&d05EXH$OJzw&f>9JvV-~<xtzpr&mJ)3# zt^4}dJ;CwH5a3Q{crP>OnfJ;0@};Mzn|G656V%rsV(N#@1DyaC>j%>yg4)_VZtpi^ z4$R~na=AT7>*IZ1AL@sFZhUwc9|;5piB`Y>L|~&3j^krablejP42`#Fv4k9O$mI$; zF%N;*>=WT2Y&Irr9@rh6L@)yJTD0r+VpD$OYqp`G5qH=Twobo1f&7qh2|N*)`RMCt z5>^5=+dBb3rrVuclg!S|FML{Dj6`FxSe&F1G{YvB49;`QE2-7B^m-<<5!u}0xots| z<ZO=2OPoHy%R7<P^ye?Td;4GaGY3ktP$(AJk|>G{P073tp-|<+t)p+>BR|ra<Kx}6 zp9P^(`c;(}RaK?3e4@NYvh3lhmf7D8Y$NrD70Xgh{acr1xh^r;=Ey0}bN}Z4ADn5# z`7_Z35rLQn@fV!3T@cu3sYXRZOw?(q(U+=l1rYG!LIqTS4wb1%)v`)c*EjlN#riFI zORLpVMG%CdCdSn7?sHM{I%^=7WY6#Nxs&Jv80AAeN<QWi_cvX!_a&yZ5Yzei!HOA( z>8=<EC*^g;nl5r9OG%cY6BHS5^LNqB+sG4UmhG=%BJ%?P001R)MObuXVRU6WV{&C- zbY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn=I&E)cX=Zr< sGB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$g8msoqyPW_ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unique.png b/web/pgadmin/misc/static/explain/img/ex_unique.png new file mode 100644 index 0000000000000000000000000000000000000000..cb70480be8a4f49369d9a974ce9461284d1a4654 GIT binary patch literal 1238 zcmV;{1S$K8P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004iP)t-s0002Z z#KgUKcgI3Ps~Q@~u&}o&Ddc5l(9X`ss&&DSHnvqK%tl7dN=mayB!;PEQjHmZrCYPX zru6a2@a(tm>b0~uF5<tRp~YT>vPSFWp6cS9>EWB(wt%)SEA8a5a-%iq-I&LARP5lb z-DPF(<-exPW%BF9vLz+pz?JIUs&=Y7>DZ_2+_~o1l-8qo)LdNR&yAk7hpyUjc&<L= z)RExHh~LMC=Fy_RTtmV?KjF-Z=+~yT<a*t~g5%7duOT6OvqIz1kK4U}xG^!fML3PY zQ|HvA<j$bIJ3G^6X1VKs(35S+RaLw1gT_uymdstaH8rt4A-G~H%wuG_M@zb8Ws;TA zW^2)iL34~eXwA;?y}#|h!R^Ar?#0IN$jR`_%<--<Hq^DqyuItEspqP!=dQ2mv9s#7 zx9hx}zpN}W)z$R0W_!S=%C9#);NbVg#O%qp*3r@OwTrE~yX?Nd?W<8{vvZEQtk|zV zN|H5LgGPX=ey69T;D1YtlFETR00001bW%=J06^y0W&i*H32;bRa{vGUNB{r;NB~C3 zYd!z~0*y&TK~zY`&6N9F(oh)3hs+U!xs^aDm&vUZae{%Mz>t6d6NpNgVwgoYFIh(3 zy7;emwsT-WPoD8Z&*S?eXP>?A`{nFI5QC)~(-9-qn4TPw8K(^79c_;qX;>yRGhrkM zmgDZ;!yxpe#VVK0K;5Sag0tJFa13pkb~v0)7iDnswA^I|Fc`!t6CSVG?Df&|5A2Mc z!yy3hc-(%<1rabC4w>YwJny3XHeUcC4=@N!Y=Y67XxiA1bfc8ZIN0SO&+|UgKRXvh zUD&C47Dj2YfB}5L&;mV(@PZ&Ly2G|eBm_^E<{w2_CCX`sM~Fq1<B1`}C&Xea%&Iq; zOraAtn&uS5sSu)=8Af8U2<cyQC6^Jh6isJYB}$L*I2jkk+%OUd1{d?;LMoL)BePGk zEL;+-QB0IFnW0^bN?v7?8Vr}lB^C%K$n~|kVljbU#y!RTm7(NDzETiDp<uWw4oSsV zYGtpCl;9o9;t`QtCtYGLmn$hZIa_^(yU7b1^-3X8DwULAxGEqp-;0rcUaP<81*7Gw zBy{A<kv%cHxiuOAn5}W8+b#20LxQz!W_B9d5|f&{uUdPr_um+(w~{uGN$q#<KYaXj zKp75?ByAo;$g$acEF)SxhLA%)^%){~kHK9IDF4aP7lhzE1{2$1^xKlu=tsIy%GLP0 z%U9sB({2~!v2K*jZ{34|T{`aYNox=7f;@(n{C?Iu7(mXM)eH3mdJKaAk6o%=pvP`N zn!Bw|K76H)j6C-5UF2YX)XG2AV35adO6;r+Ja($S4C^s4@~?d5s&8bh#{hC(D_^Jx z-eXexH}KeH7t!J|X}^=NZ1#fD;;{zEtA5=J<`#PF|I{BM#JXLtE~^v(001R)MObuX zVRU6WV{&C-bY%cCFflMKF)}SMF;p@zIy5snG&CzPH99abIGH6L0000bbVXQnWMOn= zI&E)cX=Zr<GB7bPEigGPFfmjzGdeUhIxsdXFf}?bFv^!ztN;K207*qoM6N<$f(A@n A@Bjb+ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_unknown.png b/web/pgadmin/misc/static/explain/img/ex_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d54f5c7b253978b96993ea260828a144395095 GIT binary patch literal 1088 zcmV-G1i$-<P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-s00025 z!qAqu(2ljybgR*YvC*c#(8$fuxW>>^ozY{g+H$$zaJ}Pq#prd!=Xk~Eea7c~!sL0n z;BT|sS)tRx%FtS*)o#A!TgB^2zUV@{=s>&YKf2~ayXQu|=uW=pS;FaL#_4Uz>V?ql zgTmx#uG*ix&}^sCZn)r0!09iw<{+@-AFtyivE(VU<S(@3G`8hBxaB~(<wd*ZOTFe$ zzUOPl=~<%FSE18r!{{2W;}xvqRlw(3!RL9*>ypmuTB6fvyyGgg<`JvnU&H8?(CcKb z+6}7WW5noy&+LiA<Yc7LR>0^9sp2xV<VL*aXU6Do$?BHZ?`E*vFt_Gl#_Mpx=3d3> zQNZYfzTthY(P6#i1*qX$pwV}|;(pHSdCBU($<S58=^e1-60GB4s@Sl@&}p>ZUZ&P@ z%j|o{>5S9ub++Dj%<5;W*ml6=ipuD1!|15M&|t;sdd}^2y5K>(=xE66YQW}z$LM~@ z=wip~XUObp%Itj4?KV3{{{R300d!JMQvg8b*k%9#010qNS#tmY07w7;07w8v$!k6U z00H_*L_t(Y$L-VoSJF@z2k>#Zm$&&66HySyHefJJgw$z(fRdI186mP%OejOc)GU0- z>Thp&cTUGnWA_LBjqi^;_jC5#=Xowg_45ER0W(yCfW=C5-iGWBdSGy9_=%GlaUqi- z7)9=}agTSxH_7@rUI+w3XtcKw!x1Su^>jKm6Hh#wotx+6KyX3qS=8e5Xfl=jOVUex zCY$SJ(DF(?f1kYIGpjlM+Q3>O|MFk*N?zYUx};D{l{E6&w>hhkH|4iEy=IG*tr8}& ziR$)Hxu#$u2i^f4va_4qyCc)=fD6L<KCfW%UbnKkRKg@awqsLAR5&PNlF7pVi-x=T zA@#A_G0)+r?gu!`8IsoWZc$>r-g5o!YDdRuOx8EdI)ya=f(84cqtfc00Its*zP`{t zvGm*-tI5)xw)yaY^JDU5HB1@DiXyUq6VF9xpNhu9hUnU)HhsCxm`TK0GodYv9AJ>K zpwO8V$2+zpw@(TFp)QUR#cP=s&KF1o75*B>n>;TB;RT6Mw;+beHz%@@2+C4n@q3xe zxX1(rB0fx-PLf_>Qk9e@SL44kfRHrYjx{x*Q0S;ZNGK6#A=nd5v?4T3cRC&Bgw()6 z&n4?oZ*z4HNy+sL?wE4ZCuHQu?RfR}=da`6SyFNV?OMnlOFxg0KS=w20#>Z+^Z)<= zC3HntbYx+4WjbSWWnpw>05UK!FfB1MEif@uGB7$cGdeUhD=;-WFfcfoB_03(03~!q zSaf7zbY(hiZ)9m^c>ppnF)%GKIV~_TR5CL<G&DLeHY+eSIxsNGmsP9)0000<MNUMn GLSTY1nJ@bQ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_update.png b/web/pgadmin/misc/static/explain/img/ex_update.png new file mode 100644 index 0000000000000000000000000000000000000000..a45c53f83a0593704855bb8488871e8e8c9be701 GIT binary patch literal 1090 zcmV-I1ikx-P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70003#P)t-s00016 zTU$1W!3nA2a+aZzl9IuXHZry4b*9Hbyy(lKSW3X@*Qid%s&!q&>iw+&W5()h$LMIt z>~72Kb<OPByMEiff7`u@<Gpj-zJT1nfd9QPd(rRQ!GeU*?%l(Kgwyce#Dw0(h2F-7 zjMVPm$A{m@h>_Lq;K_;M%!-%U@#D*$;?9iY%%0@Up5oAr<j$X<+wtSlkLA#z<kOJm z(V^ziqU6+(=F+0%)sp7Zqvh6<=G3I;)upcB^XA!<=+~y`*Qe&%mg(51>Dj2~+?VOv zsp{Fb>D#L7+PCQ5nd;rD?A*BN;F{~+tnA&o>));H-n#7It?J{P?cclX;jZoAyXxef z?BcKO;k@kQu<hls@8rJi=CbbQv+w1=@aDkp=(F$XweaY|@ae+v?6&di#PaRM^X<m- z@W|M;qjdlP00DGTPE!Ct=GbNc000SaNLh0L01FcU01FcV0GgZ_0007=Nkl<ZNXPAy z-B#LA5QQ<eL#ah;5tS;UMbwA_5<v)|fIxsm0YgCuG)2mv@BaclIp+XDLzfq>)m}Ik z`zl|u_nwKx@;3iqJ}~+$R5OHe*le~9W_M+Eb)VV);&7ZYr@MQ57tF=s@$q-Y6tOKY zFWZ<Eq^rzltJUgYHW0qY9ImfBj+s~b$~)|Np_(D^I2a5bC)(@vMljMeZ3shERr^4m z0k9j9!To)$N40l*d;0*Il+U+8O{EeF5Mun>Zl6PH7^x9N(m>1S^C~n`i3##!Jnm*; zhV*LqVXP05gphXrI;BEA5sz0XlFizcG0d`H|I-vdaf)Ui`bxFjrCB!Z-`K&F`2_lG zW8HeL^u3$4uQLXA^nuZXrj20OZmUD+*A=A;U0IeplNZl1u(P(dwqr=q)KgrQK@JCl z;>^E+p@=3)q}Ws)l=#)94014dCK_tO3=TIzaIq>bwt5*3%TPQ!V{>4cXY2w@vpi4H z5p%f~7?%#4`cmO#jZGLtp*Uy@&3d0|w^~NK=oCe<1FcLZ-GKRfgiQARl7;%8Pr;%T znUf=*08efhU<o1hL;@WKQ8^qA7C~fLHUsG+pZ6(3LA}y4RZ?t@Jvm83((Co|<_PjH z|Dvj=XrUD8WCI!k&sR*5kA}v!pSNfJ6<IEJ=yr%Ul7estl~^=#V{VN2CpSP8r8wXr z>T$a{bA%j*5fQuxo)|>jZr1{YRBA-{1CJ*HoZICJnIoNCF4LOJQi(<*B`9&BQ0dhg zYo(KD3q<dDK30Jnj^of*LV-ZR+!#3wqPz#EaOo)mPN(zS97+20!yp>N#m*4FIU=Af z#HdEyIudfZoB=prjNI`t<e#W9MZxd)7yi=N)=U1%xA~vu4`}JQAOw$Lx&QzG07*qo IM6N<$g4z^C1ONa4 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_values_scan.png b/web/pgadmin/misc/static/explain/img/ex_values_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..15b5ab4079cb8e2c015b4f5f10a3dbf8aa6410d3 GIT binary patch literal 913 zcmV;C18)3@P)<h;3K|Lk000e1NJLTq001%o001%w0{{R3DdBj70004fP)t-siMiW0 zh{12o?m@ljMZW2E&hL59?@+?(R>SIp)9{Ja@MXyCYRT+x%IuWb@tNB3d(Q2G(e0$& z@u=SNj@0gw*6*+3^985jNWbYDuH#$9>o~XNP`>9?z~@=P=Z4YkYscts$mx~W?|Po8 zrNQK8meIkFHu36*?c-qX<6!dYhx6)(@8e(Z<X`jahxF@*@Z?|d<X`pchw|iK_Unh? z@Av20E9lxQ=-Mjk+bZnaD(>4V@7pT#<zLt8_37Fw>)R^r+bZweD)8JY^yOdH>GbpD zU-ji*_v?rF>xbLDiPY)z_T^vG==1U1D)QVa^V}-;<zLa~^7Py)_~l>q+$#9yU-|2Y z`s|0!=JL+v^7-ap`|O6y<?;31D)-$g_}wY`=3mR?@%G&+`{rND<M8?2DahmS`Rs@M z?1snV@W$fr{N`W%?1shR@B7{<{N5@3=3n>SDf-<h{^no8;O_n2DgNw+z~An<+wA_{ zDgWkQ)amoS-tDc{=`>ap0ssI20d!JMQvg8b*k%9#010qNS#tmY3ljhU3ljkVnw%H_ z00FH@L_t(Y$L-b0a)Lk*24Ek?nFomRW_gGUK~X^z7hFIQqoPPyTuOQNU}g{;#Yj~u zhm?Jq%hywM|1~5M&-$-bf~P9QA@C)YD!#&4B$dhJ^6-HRlK><UDZb@$)Hi|e6h+aI z7lL#eAd=5jtC&#LT8)Xk5M;BM1g#-eV_6OzX@=ukmluLU0gw}e6wC6MaC~zhM3C?# zXpU=qVA33nA0Xiih4FYO5~N%P_eS3qM6pMZN(IEs1gO_R%)p!pq$!4J!B~W0dA{*T zU_hti6P|CPal)1$2<_;=bi0@Y8wgGI=I8hOm;|k%FdTl$=-8HJWkw8nG`bFqIFuv> z5m{ALg&>p3bzpku)=*JRlO)sW-M}cOX=((S&+i6irfAxdAd5xpz^qoW1LG6e7Dc)D zP+)8u6H)Rf`%_@fM3(#wc;Boj%jm#tw?0u-yn)kXbuBtDXA-pbh^`yxxHJr711}%G z-3~o|;r(g)dX0&(b{s2Az~Sh+#{;pMQ)_F3i9?ViuwB>2PwdUWSk8WbK|JGSEO{p| n8_Tjb@b)wQYk!?*{c(K(wSJimSdJ6(00000NkvXXu0mjfih%ky literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png b/web/pgadmin/misc/static/explain/img/ex_window_aggregate.png new file mode 100644 index 0000000000000000000000000000000000000000..1f858be1cee3f5d8f2b67f55d730e6d3f43e9b42 GIT binary patch literal 2021 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png b/web/pgadmin/misc/static/explain/img/ex_worktable_scan.png new file mode 100644 index 0000000000000000000000000000000000000000..b51e0b3f4c61ba166b69bd7f32cb23dc8428429e GIT binary patch literal 1965 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 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exclude.png b/web/pgadmin/misc/static/explain/img/exclude.png new file mode 100644 index 0000000000000000000000000000000000000000..bd62eef6410d9315857d2e6d246770e8b65b8f47 GIT binary patch literal 725 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47y|-)LR^8|wi}<ymTvVw_QrY1 zLC3?d^*UDhFWLA1|9`)wM`KREbvXQ5A-=(6%9fR9ZhU_6^4^pwS28lLWMw^=HS5>= z_isLZP1<@%wQ`Qjk=K%*nNgG09JqAnY+~Zm($d$dsZT2^E~KQ~e)?Lsd6{J1L`ko# z8QYH^XzhAZSorVPuP+-md|tBT-`~HFYif>6nkJPuNuqp?YIOD56Ib^8`rV6+d^K<0 zzkmPUtXQ!pGFqZ!hGg3swe*g4XK!wIaz5qe_HfFSrwbQu^AC`0S|K@Qk7Uk-*~hPM zEhsq<82I=1?;BI6UhV1m_vg>S@bIm*jgk|0NG?2Of9R!T^@7Cpr%znEwc5~Vm%sly zUEQ5NKC5l*c3rqFx8Q{2nrn7@9?A4<w%>5&&c`3`Z{FOOoV;9Hdxfs<!JM4Ox9?6m zenWfBW$A4XY?hzYUUH^<`Bv54PXhWDq@H_cwegx-ao6F7A05CjWh@Eu3ubV5b|VeM zN%D4g;b^-zwF=1LEbxdd2GSm2>~=ES4#-&V>Eak7aXC5R07H*Y2Gbdx45l?XZ+LiQ zWMmY~)Ws(}c=qt=V{riyAu&Nw;pq&V9$ucOPn<e=Qd>hyv$&ZhB;@K9Q<JS*N=v?e zImpD;=5|bN*|M}_&%~xBFluK@M_UI6S4XqEt8Zx7+`W4C?)K%=xA(7?_c&m$V4z{4 zVq&6Wqh!RTA|NX)Ek1w3j45*_&6>t1bmBw`i*--4qPDWM%7n?><t2V{=CjN{U1V)w zV3-jtUHUai{xs0(swJ)wB`Jv|saDBFsX&Us$iUE0*8qr2Lkumf3@ojTjkFEStPBi} hcbK)IXvob^$xN%ntzp~MJ}aOG22WQ%mvv4FO#q89Jv#sZ literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension-sm.png b/web/pgadmin/misc/static/explain/img/extension-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..432d2f44231c1f88e787091060efc5125d80ef64 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}QGic~E0BJDv+cp5$Qv6qzrVk7 zW3&9@vzBik`G5Ho|K-)uTicc2-1GkNGyU0x%oo?3fBedPak1gnHlr`^;(z|izO~Kb z%lm|1zjI$+bN~H2|Mm{mcMpR9{3*J*S>f3^`;Si}e|^pQ`={jETDdE$#Qyy)dv><$ z|KAGswyocQwlbCk`2{mLJiCzw<Zu>vL>2>S4={E+nQaGT<aoL`hDcoQ?f2wsP!M2o z7l{eDQ+~(c|9@BE84^1Kx361bY|Bu`qQb-J62DBxZ_<p5BE`pwna}6wxpa1%>e!Vz zahdU=*X&ESFOpJE*&;e)`qd3*DpaT5u9JDLS%3P((k)@<ZbaLzV+h!Of4=?`KK92q z=3fE@l4^--L`h0wNvc(HQ7VvPFfuSS&^0vDH82b@GO#i+wlXo*HZZj^FqrpFZxxD$ o-29Zxv`UBu152<5plTB<12c$*Q`1A&05vdpy85}Sb4q9e01}k2!2kdN literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extension.png b/web/pgadmin/misc/static/explain/img/extension.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c533347883fc1dec73bcb21b32fc54e3c31732 GIT binary patch literal 996 zcmV<A0~`E_P)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%`cO<%MQ2zLf_6I6&9|zdd99>-@a*2m!Junh7N)|bRf|-bx|zVboSKha_w(lG z;mc-L4XVVcQjb)R!IoN>UTm6cdTlP+)48aeY_F(+!qvh)fIq$I$ak@QM1Demb2p-y zZNIpg%*U?Z+|0eUmR?Q)@#@yLtA3u9XFhv8mdv0tb~C!Ok)4xckc3Wsa4?*aUD?pH z@afX-<;s|gP-<HecxWLITMn+{ye)Dq{QLL&`11Mo?Dg>A^X%E{;lk+My5`xk<JGC) z(V?J^Pa0qr9%URUZYXJ}aH`|EXsd7=V;MkvKHbcisFznYY9*e@qsi^kq0p+c;k~!# z!?5MPqv5li->#6?p?1NAale3n)0NuDkgb|nMQ$vEwur;)&X(P%klLe(*qwsbn0(Ze z&%lqBg+*3S1ZY?dnutTImr{GNfpyZ2etkM9XCNqTCtr9wihVOAV;iN_u6D(TK#xcf zTn`v!7(bOtw4`b=XCQ>Lht=`it<|(#mtSF?W<QQcm$;T>m1BZ;G0*SUx8%WGt7&4B zV3D+tb8RIwgF3Luu#bN^7G4v==*yVRp-_@kjmeoSdoaG!zSzWv!K`UHUKC!MVuZSj zaIAJVdpAyF9vxyClh&g+jY8GGe$u;klYuouT@*iVD?w)>Y;7EsekVC?DRR1gZ_tQZ zyKv99ZOyY~z@}84hBK{_JHn(!l6fLVbTnhFZfMSfV$6Lul0qhGC2*Z?NP<TvhBL~q zUB|0c#ivccpg)Ro98G#WT*`P>$a6}(W;2>aI;l}Wz+t|fIeljlScFSfreaXWZ%f2# zMZ#t~zg?k^OOAUphI1*4cr3V}Qns8&igY1@Y#D@Y7H?b$T8UCtsbn_2S%i2!rk!)h z!>EaMCcvamyR?(W!KK8$qF<3+9BCaAUJ)8<9X6LmEss1DV->ZTL3e2=8EP9)hfaum zLy>wXERsEdsDEo(3zmE$ex`jsyImG&7=LOOfol~TcO*%INEmJ%7i}B|YRn1%0004W zQchC<K<3zH00001VoOIv0Eh)0NB{r;32;bRa{vGf6951U69E94oEQKA00(qQO+^RW z0~-xG4!&HBF8}}lR!KxbR2b7^U?3j2xS;VvLXbtwTz~>0W=QhVA)yH_FkL{}1;huk zpaKCQKz@=7s`{i97i0@vl2TS8w1C7?R&G7y;)1Nm<<OZkC{A-h<6}A<CjbDaP8qDe SR_4e60000<MNUMnLSTaX-^L37 literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/extensions.png b/web/pgadmin/misc/static/explain/img/extensions.png new file mode 100644 index 0000000000000000000000000000000000000000..eed7ca97a33ef595f448b8621168d531f86d51d5 GIT binary patch literal 1017 zcmV<V0|xwwP)<h;3K|Lk000e1NJLTq000mG000mO0{{R3C@l|D00001b5ch_0Itp) z=>Px%_fSk!MS^xZ(#^N3p?R&Od+_Yu$ibj%T^6RorB#bmn!1_5x}2JiUH9|m=i$p{ zRt>7esZx(rkHMB&m|kp}YkF-i+S9qHoNTYCfx^|oK7c>H>Bx7neMEjjfO9vZnQgzg znaszo-`vc-ww7K_0rBeAwyS=gm1jPCJeJI$Gj=n&vyq*XV~~VSeQ+?GkzLu)v+(KC z?&Zpui%@D?5_o7K5L*te<Gd|$E&TiU`}p$t_U!fW;PdR+>*2!a-MZ%4vg6gM;L)L= zk53w479M3BDQ+lfsBo&|xoE3!8)F$jd_LXGn5dUmHEJcE$)m~b(xK3*v*EqB=fkk& zzN6u@o!_pI*P(X7g>k=tf76xP$dIj?SVe9ugSLpn>&}+lsF2#DiP)Wj)|h<Mlh449 zm4!uCPy}dL4Vs8UtCv!Hv4M5cjedPPC}$ujZ6{xNJBocXBx4(;)vk8Mhd_@=5nK-# zWf(t|O0=YEF=rrzvxn93+^yBLT$f*Ao@PIeN0+#kWR+urcQMcJ*SF-sT&rnflVFjw zkaKM%G=n;@$*_-qITl_M!syGG&7n||RE^1*D|;}$)4tfmhrz6AIbIZAnqq{yi*T%V zHhVWtV;&u18I#tdIE_NpzkbrYc9VfMLtPX<ZYx1&B5Z9Om3}8VZ7FiPes9o-TDx%1 zw{6X{Wx%FXorW{5k~_krMv{3VMsze|t!`+}gJR5mHj+XnY9(-;Zb*VhCx$c1uU*Hh zRmG=Gz@R^havV*1JY33nR>*Toyk;|+MLMZbK)_+XojHAH5m<yvR;FT5#&1i+YDL0k zJHK6_k4uhwGlp|1i+C)!pi;J+M~ZYIf@~RtZ5D4_30jF#R;gq*y;+2KJ*J&=$it|K zbtb^1PrI~}#=)h;zM@}|T^wm05?&D+Y8^J0MJ<m!6k`>&nL&4HC>d%SP=`*4d_$3X zCoGaZfT(|KS__tZB7UZQKD%8OXc&KL7J+LO8+Rm0f=C!{9T#mJ7UDFE00001bW%=J z06^y0W&i*H0b)x>L;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru+XEXB z6Cp(Rbcp}}0B%V{K~xyiU68R2z#t3+nS(tt!3~hY^vGg42FL=`EENNm0{M!6-y1;) zQxFazvL_cK*b<_okFg0d8Hc#V=Eh`)h+yZmplehnlNZEdtgQ@hX0CNeIWEpxw!oyN ndc~tsp9TlidOzOC&-)*|KH)3pD2ngr00000NkvXXu0mjf<KNUz literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable-sm.png b/web/pgadmin/misc/static/explain/img/exttable-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..acd43cb8abab6ef38daf34ff6d7544153a11dacf GIT binary patch literal 612 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47`X#{LR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)^XY$8$A0G@_?f)(TiB-0o~u9DE`4h_ z@3s2Om(8dDdI7mh-fGNz8JxJ$(RuCl>$mUSyLbQo{YQ@;J%0Rn>9T9)mKA9e*Bv-; z!q9k*y7s}c^63vAJOIkOd8|>@*q@f(clYkyWy_XDM0Trbo^<nAscUdhS#3sp`^5F@ z*S~u8DlvJNy7pxi^{qR09)J1r<?Gk4&!4|-WV%sNW#!y?Ya^o8sA?W7EL!yO<Hxse z-}X<~s-}6=(71d4{Dn`SK5cATs;+%VU9<bdiL;%Z6I)tVJ$drv&6_t59=vw<+ErTC zQw{Rh4~>~Gc%JJ_00swRNswPKgTu2MX+REVfk$L9koEv$x0Bg+K*j`57sn8Z%gG4} zOa@Af9Sp+8+}hIC?Ck2|<}MBG)BEEc0z4vIL{>Gq^Qb83DJpS_PM9=p;?&9E0U<$c zTq{<rTA7`ZmHE2Bfwko87hay;9$%lc3z#+)6+IK17IrPoEP&B6+Pa$ET|Heqd_}|T z-R;Y#Z{6O%UOwc2y~2g=!)h89Dk9JL?rkX8V67z4`B96(W2)e}i60vRfNoPQag8WR zNi0dVN-jzTQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTd cHGouG8JIydoSGiG2B?9-)78&qol`;+0LVQH?EnA( literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttable.png b/web/pgadmin/misc/static/explain/img/exttable.png new file mode 100644 index 0000000000000000000000000000000000000000..5d84035feea62d53d457481178b1bcbe9622f856 GIT binary patch literal 793 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47;6K3LR^7d#i`GGFZ`c${`aEG zUw7Sjd-49u`;VVLefIp>vuC#+K3#L}dGf{=db3}2pa0)_=3m{3Kc$C%<?Q>BxZ_*c zrqAAMJ~%9YXTIQ#?wnU@GhViy`J27(hvTw$W((iw&U_Y~)1HyF{qEhn_wL=hfB*i2 z2M-=TeE8_mqsNaQ8yXiV>iW%}zd>1TV^GL$BjYL^{S(WU9oVt+prXnmSNFZkm#=*C z<jL~o%k>TF^o@>PyZ-vst5*{zPLflcU|_QU>a|B#uU=JF?bJ2cziipY_3PKae*OB& zm8%-sEqaEB)ikG?m>;=w=lPpAZ{EIr`|{<>zP<^HDjPJkuS}Y>_5J(zA3l8e^y$;P zckfoNT)BGn>N#`fDXPqIbUAEeo3EjBs<&_JrcIlkKYzY=?-6CSwcft_U%!6i?2@ga zbAH+K$Dcoc{`&RnzI`WD)Hj5LAKkcd)7Gt9lT#YiwN7;R-um|K+wv9LmDM(Tcy0Rl z@#D5_+u{=nRW-JDc3)AL{8UY|HzVudq)BroPg$ri@$mwIO;dmoz*rLG7tG-B>_!@p z!&%@FSq!8-z}W3%wjGdh+0(@_MB;LCLV^n;4-Zd|&l#OHId5d<%!#>Uvqyo^u8z@B zF;Otku#nSp1DBm9qhscRhMqMtE)H>yfu51Bp}w)6&cZqimabjQ@@VyoS1+4cMR<97 zd#?KUoIRtfbCAhvS=cqRZDrs1`uxr%FfOPQ4>vF8_xIM%-_X$2-@kPI{CbCkfC7#P z2U8Or8zmzxD>XAS4xIy%;`1lWcrs_sq*>GW#5zu&ICF}R^VG?+r}Y`QMZ`qYkF!mE zGG*G-@CFvG)vNY8H+eN(zQmoCbx`Y7z#e{vFBY0Te&TE7f!<Rsag8WRNi0dVN-jzT zQVd20h6cKZM!E)uAw~vPCdO7KCfWw3Rt5$ZGgakKH00)|WTsU@G#FTdHGouG8JIyd UoSGiG2B?9-)78&qol`;+0Q{<O$^ZZW literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/img/exttables.png b/web/pgadmin/misc/static/explain/img/exttables.png new file mode 100644 index 0000000000000000000000000000000000000000..c5dfbd454ed33727bd1deeb87c62f8671f6a5a03 GIT binary patch literal 662 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GXl47^MPyLR^7d#i`G`&i$Km{^#1O zpHAI*b?@=>XV0HMd-m+;jb~*$Ul`1J(Q)=)(1uT&ufDx|_ipp)e^tkR=O6f)yz^Vw zrq7<MKiDpPYdG(<`plR2?%iuX{nra9vgEDdjF%cSU*5le-z{*Hjoqv(SFS&L^yu;9 z$BCh54YV)SY`ps5!GohmFPT|vP}AIAUOws6@q1>vXAHE?^>wU&`SRt%hYy!6TNV*D zT}|t>v;9UL?W?Amt7goYwSN8jSFc`8IQ7}h=Aef5HBHT(=Pz7){rdI(-PetE&Kqf+ zTC?J?x9>_dt@Dk|J3fB=`1bAF+~nQb+SeRSH>_B(;_1_;Rn;?8HFg`BEWUQ_zJ=bg zri$H9o;-Q;=FOu=PwX9+YwPW<2KnxXa>IqjgMEvDp~F}b<QL4~@a#q!ki%Kv5m^kR zJ;2!QWVRiUvDwqbF+}2W?0HwQLk<G27xhdW8XmB4zY~jTVks}b`QPk?8Z+O@ht}mE zxDUR+@ZDiy$V$_wu1ha@gBJAuXUmw$IQdLNWLm+2wv7?FW$l-rva#qG$_eeUt7l;6 zYfsQPQ#3I{XWjwDPG7CLC)J97I!!#j(8XtG(AulgXTzi?C<q+hI5%(o`R%TodS@Ig zFq!9*{+X5YhEDkFv(xUs<#&JSY%y0q+H23fcl??hCZB62%C0l7Vc_x-dugW}eiG<> z)e_f;l9a@fRIB8oR3OD*WMF8ZYiOivU>IU#U}a)#Wn!XjU}|MxU@=ow4n;$5eoAIq iB}9XPC0GMUwUvPxM8m1+p=*E|7(8A5T-G@yGywoZHZsuw literal 0 HcmV?d00001 diff --git a/web/pgadmin/misc/static/explain/js/snap.svg-min.js b/web/pgadmin/misc/static/explain/js/snap.svg-min.js new file mode 100644 index 0000000..6567d19 --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg-min.js @@ -0,0 +1,21 @@ +// Snap.svg 0.4.1 +// +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// build: 2015-04-13 + +!function(a){var b,c,d="0.4.2",e="hasOwnProperty",f=/[\.\/]/,g=/\s*,\s*/,h="*",i=function(a,b){return a-b},j={n:{}},k=function(){for(var a=0,b=this.length;b>a;a++)if("undefined"!=typeof this[a])return this[a]},l=function(){for(var a=this.length;--a;)if("undefined"!=typeof this[a])return this[a]},m=function(a,d){a=String(a);var e,f=c,g=Array.prototype.slice.call(arguments,2),h=m.listeners(a),j=0,n=[],o={},p=[],q=b;p.firstDefined=k,p.lastDefined=l,b=a,c=0;for(var r=0,s=h.length;s>r;r++)"zIndex"in h[r]&&(n.push(h[r].zIndex),h[r].zIndex<0&&(o[h[r].zIndex]=h[r]));for(n.sort(i);n[j]<0;)if(e=o[n[j++]],p.push(e.apply(d,g)),c)return c=f,p;for(r=0;s>r;r++)if(e=h[r],"zIndex"in e)if(e.zIndex==n[j]){if(p.push(e.apply(d,g)),c)break;do if(j++,e=o[n[j]],e&&p.push(e.apply(d,g)),c)break;while(e)}else o[e.zIndex]=e;else if(p.push(e.apply(d,g)),c)break;return c=f,b=q,p};m._events=j,m.listeners=function(a){var b,c,d,e,g,i,k,l,m=a.split(f),n=j,o=[n],p=[];for(e=0,g=m.length;g>e;e++){for(l=[],i=0,k=o.length;k>i;i++)for(n=o[i].n,c=[n[m[e]],n[h]],d=2;d--;)b=c[d],b&&(l.push(b),p=p.concat(b.f||[]));o=l}return p},m.on=function(a,b){if(a=String(a),"function"!=typeof b)return function(){};for(var c=a.split(g),d=0,e=c.length;e>d;d++)!function(a){for(var c,d=a.split(f),e=j,g=0,h=d.length;h>g;g++)e=e.n,e=e.hasOwnProperty(d[g])&&e[d[g]]||(e[d[g]]={n:{}});for(e.f=e.f||[],g=0,h=e.f.length;h>g;g++)if(e.f[g]==b){c=!0;break}!c&&e.f.push(b)}(c[d]);return function(a){+a==+a&&(b.zIndex=+a)}},m.f=function(a){var b=[].slice.call(arguments,1);return function(){m.apply(null,[a,null].concat(b).concat([].slice.call(arguments,0)))}},m.stop=function(){c=1},m.nt=function(a){return a?new RegExp("(?:\\.|\\/|^)"+a+"(?:\\.|\\/|$)").test(b):b},m.nts=function(){return b.split(f)},m.off=m.unbind=function(a,b){if(!a)return void(m._events=j={n:{}});var c=a.split(g);if(c.length>1)for(var d=0,i=c.length;i>d;d++)m.off(c[d],b);else{c=a.split(f);var k,l,n,d,i,o,p,q=[j];for(d=0,i=c.length;i>d;d++)for(o=0;o<q.length;o+=n.length-2){if(n=[o,1],k=q[o].n,c[d]!=h)k[c[d]]&&n.push(k[c[d]]);else for(l in k)k[e](l)&&n.push(k[l]);q.splice.apply(q,n)}for(d=0,i=q.length;i>d;d++)for(k=q[d];k.n;){if(b){if(k.f){for(o=0,p=k.f.length;p>o;o++)if(k.f[o]==b){k.f.splice(o,1);break}!k.f.length&&delete k.f}for(l in k.n)if(k.n[e](l)&&k.n[l].f){var r=k.n[l].f;for(o=0,p=r.length;p>o;o++)if(r[o]==b){r.splice(o,1);break}!r.length&&delete k.n[l].f}}else{delete k.f;for(l in k.n)k.n[e](l)&&k.n[l].f&&delete k.n[l].f}k=k.n}}},m.once=function(a,b){var c=function(){return m.unbind(a,c),b.apply(this,arguments)};return m.on(a,c)},m.version=d,m.toString=function(){return"You are running Eve "+d},"undefined"!=typeof module&&module.exports?module.exports=m:"function"==typeof define&&define.amd?define("eve",[],function(){return m}):a.eve=m}(this),function(a,b){if("function"==typeof define&&define.amd)define(["eve"],function(c){return b(a,c)});else if("undefined"!=typeof exports){var c=require("eve");module.exports=b(a,c)}else b(a,a.eve)}(window||this,function(a,b){var c=function(b){var c={},d=a.requestAnimationFrame||a.webkitRequestAnimationFrame||a.mozRequestAnimationFrame||a.oRequestAnimationFrame||a.msRequestAnimationFrame||function(a){setTimeout(a,16)},e=Array.isArray||function(a){return a instanceof Array||"[object Array]"==Object.prototype.toString.call(a)},f=0,g="M"+(+new Date).toString(36),h=function(){return g+(f++).toString(36)},i=Date.now||function(){return+new Date},j=function(a){var b=this;if(null==a)return b.s;var c=b.s-a;b.b+=b.dur*c,b.B+=b.dur*c,b.s=a},k=function(a){var b=this;return null==a?b.spd:void(b.spd=a)},l=function(a){var b=this;return null==a?b.dur:(b.s=b.s*a/b.dur,void(b.dur=a))},m=function(){var a=this;delete c[a.id],a.update(),b("mina.stop."+a.id,a)},n=function(){var a=this;a.pdif||(delete c[a.id],a.update(),a.pdif=a.get()-a.b)},o=function(){var a=this;a.pdif&&(a.b=a.get()-a.pdif,delete a.pdif,c[a.id]=a)},p=function(){var a,b=this;if(e(b.start)){a=[];for(var c=0,d=b.start.length;d>c;c++)a[c]=+b.start[c]+(b.end[c]-b.start[c])*b.easing(b.s)}else a=+b.start+(b.end-b.start)*b.easing(b.s);b.set(a)},q=function(){var a=0;for(var e in c)if(c.hasOwnProperty(e)){var f=c[e],g=f.get();a++,f.s=(g-f.b)/(f.dur/f.spd),f.s>=1&&(delete c[e],f.s=1,a--,function(a){setTimeout(function(){b("mina.finish."+a.id,a)})}(f)),f.update()}a&&d(q)},r=function(a,b,e,f,g,i,s){var t={id:h(),start:a,end:b,b:e,s:0,dur:f-e,spd:1,get:g,set:i,easing:s||r.linear,status:j,speed:k,duration:l,stop:m,pause:n,resume:o,update:p};c[t.id]=t;var u,v=0;for(u in c)if(c.hasOwnProperty(u)&&(v++,2==v))break;return 1==v&&d(q),t};return r.time=i,r.getById=function(a){return c[a]||null},r.linear=function(a){return a},r.easeout=function(a){return Math.pow(a,1.7)},r.easein=function(a){return Math.pow(a,.48)},r.easeinout=function(a){if(1==a)return 1;if(0==a)return 0;var b=.48-a/1.04,c=Math.sqrt(.1734+b*b),d=c-b,e=Math.pow(Math.abs(d),1/3)*(0>d?-1:1),f=-c-b,g=Math.pow(Math.abs(f),1/3)*(0>f?-1:1),h=e+g+.5;return 3*(1-h)*h*h+h*h*h},r.backin=function(a){if(1==a)return 1;var b=1.70158;return a*a*((b+1)*a-b)},r.backout=function(a){if(0==a)return 0;a-=1;var b=1.70158;return a*a*((b+1)*a+b)+1},r.elastic=function(a){return a==!!a?a:Math.pow(2,-10*a)*Math.sin(2*(a-.075)*Math.PI/.3)+1},r.bounce=function(a){var b,c=7.5625,d=2.75;return 1/d>a?b=c*a*a:2/d>a?(a-=1.5/d,b=c*a*a+.75):2.5/d>a?(a-=2.25/d,b=c*a*a+.9375):(a-=2.625/d,b=c*a*a+.984375),b},a.mina=r,r}("undefined"==typeof b?function(){}:b),d=function(a){function c(a,b){if(a){if(a.nodeType)return w(a);if(e(a,"array")&&c.set)return c.set.apply(c,a);if(a instanceof s)return a;if(null==b)return a=y.doc.querySelector(String(a)),w(a)}return a=null==a?"100%":a,b=null==b?"100%":b,new v(a,b)}function d(a,b){if(b){if("#text"==a&&(a=y.doc.createTextNode(b.text||b["#text"]||"")),"#comment"==a&&(a=y.doc.createComment(b.text||b["#text"]||"")),"string"==typeof a&&(a=d(a)),"string"==typeof b)return 1==a.nodeType?"xlink:"==b.substring(0,6)?a.getAttributeNS(T,b.substring(6)):"xml:"==b.substring(0,4)?a.getAttributeNS(U,b.substring(4)):a.getAttribute(b):"text"==b?a.nodeValue:null;if(1==a.nodeType){for(var c in b)if(b[z](c)){var e=A(b[c]);e?"xlink:"==c.substring(0,6)?a.setAttributeNS(T,c.substring(6),e):"xml:"==c.substring(0,4)?a.setAttributeNS(U,c.substring(4),e):a.setAttribute(c,e):a.removeAttribute(c)}}else"text"in b&&(a.nodeValue=b.text)}else a=y.doc.createElementNS(U,a);return a}function e(a,b){return b=A.prototype.toLowerCase.call(b),"finite"==b?isFinite(a):"array"==b&&(a instanceof Array||Array.isArray&&Array.isArray(a))?!0:"null"==b&&null===a||b==typeof a&&null!==a||"object"==b&&a===Object(a)||J.call(a).slice(8,-1).toLowerCase()==b}function f(a){if("function"==typeof a||Object(a)!==a)return a;var b=new a.constructor;for(var c in a)a[z](c)&&(b[c]=f(a[c]));return b}function h(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return a.push(a.splice(c,1)[0])}function i(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),g=d.cache=d.cache||{},i=d.count=d.count||[];return g[z](f)?(h(i,f),c?c(g[f]):g[f]):(i.length>=1e3&&delete g[i.shift()],i.push(f),g[f]=a.apply(b,e),c?c(g[f]):g[f])}return d}function j(a,b,c,d,e,f){if(null==e){var g=a-c,h=b-d;return g||h?(180+180*D.atan2(-h,-g)/H+360)%360:0}return j(a,b,e,f)-j(c,d,e,f)}function k(a){return a%360*H/180}function l(a){return 180*a/H%360}function m(a){var b=[];return a=a.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g,function(a,c,d){return d=d.split(/\s*,\s*|\s+/),"rotate"==c&&1==d.length&&d.push(0,0),"scale"==c&&(d.length>2?d=d.slice(0,2):2==d.length&&d.push(0,0),1==d.length&&d.push(d[0],0,0)),b.push("skewX"==c?["m",1,0,D.tan(k(d[0])),1,0,0]:"skewY"==c?["m",1,D.tan(k(d[0])),0,1,0,0]:[c.charAt(0)].concat(d)),a}),b}function n(a,b){var d=ab(a),e=new c.Matrix;if(d)for(var f=0,g=d.length;g>f;f++){var h,i,j,k,l,m=d[f],n=m.length,o=A(m[0]).toLowerCase(),p=m[0]!=o,q=p?e.invert():0;"t"==o&&2==n?e.translate(m[1],0):"t"==o&&3==n?p?(h=q.x(0,0),i=q.y(0,0),j=q.x(m[1],m[2]),k=q.y(m[1],m[2]),e.translate(j-h,k-i)):e.translate(m[1],m[2]):"r"==o?2==n?(l=l||b,e.rotate(m[1],l.x+l.width/2,l.y+l.height/2)):4==n&&(p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.rotate(m[1],j,k)):e.rotate(m[1],m[2],m[3])):"s"==o?2==n||3==n?(l=l||b,e.scale(m[1],m[n-1],l.x+l.width/2,l.y+l.height/2)):4==n?p?(j=q.x(m[2],m[3]),k=q.y(m[2],m[3]),e.scale(m[1],m[1],j,k)):e.scale(m[1],m[1],m[2],m[3]):5==n&&(p?(j=q.x(m[3],m[4]),k=q.y(m[3],m[4]),e.scale(m[1],m[2],j,k)):e.scale(m[1],m[2],m[3],m[4])):"m"==o&&7==n&&e.add(m[1],m[2],m[3],m[4],m[5],m[6])}return e}function o(a){var b=a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||a.node.parentNode&&w(a.node.parentNode)||c.select("svg")||c(0,0),d=b.select("defs"),e=null==d?!1:d.node;return e||(e=u("defs",b.node).node),e}function p(a){return a.node.ownerSVGElement&&w(a.node.ownerSVGElement)||c.select("svg")}function q(a,b,c){function e(a){if(null==a)return I;if(a==+a)return a;d(j,{width:a});try{return j.getBBox().width}catch(b){return 0}}function f(a){if(null==a)return I;if(a==+a)return a;d(j,{height:a});try{return j.getBBox().height}catch(b){return 0}}function g(d,e){null==b?i[d]=e(a.attr(d)||0):d==b&&(i=e(null==c?a.attr(d)||0:c))}var h=p(a).node,i={},j=h.querySelector(".svg---mgr");switch(j||(j=d("rect"),d(j,{x:-9e9,y:-9e9,width:10,height:10,"class":"svg---mgr",fill:"none"}),h.appendChild(j)),a.type){case"rect":g("rx",e),g("ry",f);case"image":g("width",e),g("height",f);case"text":g("x",e),g("y",f);break;case"circle":g("cx",e),g("cy",f),g("r",e);break;case"ellipse":g("cx",e),g("cy",f),g("rx",e),g("ry",f);break;case"line":g("x1",e),g("x2",e),g("y1",f),g("y2",f);break;case"marker":g("refX",e),g("markerWidth",e),g("refY",f),g("markerHeight",f);break;case"radialGradient":g("fx",e),g("fy",f);break;case"tspan":g("dx",e),g("dy",f);break;default:g(b,e)}return h.removeChild(j),i}function r(a){e(a,"array")||(a=Array.prototype.slice.call(arguments,0));for(var b=0,c=0,d=this.node;this[b];)delete this[b++];for(b=0;b<a.length;b++)"set"==a[b].type?a[b].forEach(function(a){d.appendChild(a.node)}):d.appendChild(a[b].node);var f=d.childNodes;for(b=0;b<f.length;b++)this[c++]=w(f[b]);return this}function s(a){if(a.snap in V)return V[a.snap];var b;try{b=a.ownerSVGElement}catch(c){}this.node=a,b&&(this.paper=new v(b)),this.type=a.tagName||a.nodeName;var d=this.id=S(this);if(this.anims={},this._={transform:[]},a.snap=d,V[d]=this,"g"==this.type&&(this.add=r),this.type in{g:1,mask:1,pattern:1,symbol:1})for(var e in v.prototype)v.prototype[z](e)&&(this[e]=v.prototype[e])}function t(a){this.node=a}function u(a,b){var c=d(a);b.appendChild(c);var e=w(c);return e}function v(a,b){var c,e,f,g=v.prototype;if(a&&"svg"==a.tagName){if(a.snap in V)return V[a.snap];var h=a.ownerDocument;c=new s(a),e=a.getElementsByTagName("desc")[0],f=a.getElementsByTagName("defs")[0],e||(e=d("desc"),e.appendChild(h.createTextNode("Created with Snap")),c.node.appendChild(e)),f||(f=d("defs"),c.node.appendChild(f)),c.defs=f;for(var i in g)g[z](i)&&(c[i]=g[i]);c.paper=c.root=c}else c=u("svg",y.doc.body),d(c.node,{height:b,version:1.1,width:a,xmlns:U});return c}function w(a){return a?a instanceof s||a instanceof t?a:a.tagName&&"svg"==a.tagName.toLowerCase()?new v(a):a.tagName&&"object"==a.tagName.toLowerCase()&&"image/svg+xml"==a.type?new v(a.contentDocument.getElementsByTagName("svg")[0]):new s(a):a}function x(a,b){for(var c=0,d=a.length;d>c;c++){var e={type:a[c].type,attr:a[c].attr()},f=a[c].children();b.push(e),f.length&&x(f,e.childNodes=[])}}c.version="0.4.0",c.toString=function(){return"Snap v"+this.version},c._={};var y={win:a.window,doc:a.window.document};c._.glob=y;{var z="hasOwnProperty",A=String,B=parseFloat,C=parseInt,D=Math,E=D.max,F=D.min,G=D.abs,H=(D.pow,D.PI),I=(D.round,""),J=Object.prototype.toString,K=/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i,L=(c._.separator=/[,\s]+/,/[\s]*,[\s]*/),M={hs:1,rg:1},N=/([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,O=/([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/gi,P=/(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/gi,Q=0,R="S"+(+new Date).toString(36),S=function(a){return(a&&a.type?a.type:I)+R+(Q++).toString(36)},T="http://www.w3.org/1999/xlink",U="http://www.w3.org/2000/svg",V={};c.url=function(a){return"url('#"+a+"')"}}c._.$=d,c._.id=S,c.format=function(){var a=/\{([^\}]+)\}/g,b=/(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g,c=function(a,c,d){var e=d;return c.replace(b,function(a,b,c,d,f){b=b||d,e&&(b in e&&(e=e[b]),"function"==typeof e&&f&&(e=e()))}),e=(null==e||e==d?a:e)+""};return function(b,d){return A(b).replace(a,function(a,b){return c(a,b,d)})}}(),c._.clone=f,c._.cacher=i,c.rad=k,c.deg=l,c.sin=function(a){return D.sin(c.rad(a))},c.tan=function(a){return D.tan(c.rad(a))},c.cos=function(a){return D.cos(c.rad(a))},c.asin=function(a){return c.deg(D.asin(a))},c.acos=function(a){return c.deg(D.acos(a))},c.atan=function(a){return c.deg(D.atan(a))},c.atan2=function(a){return c.deg(D.atan2(a))},c.angle=j,c.len=function(a,b,d,e){return Math.sqrt(c.len2(a,b,d,e))},c.len2=function(a,b,c,d){return(a-c)*(a-c)+(b-d)*(b-d)},c.closestPoint=function(a,b,c){function d(a){var d=a.x-b,e=a.y-c;return d*d+e*e}for(var e,f,g,h,i=a.node,j=i.getTotalLength(),k=j/i.pathSegList.numberOfItems*.125,l=1/0,m=0;j>=m;m+=k)(h=d(g=i.getPointAtLength(m)))<l&&(e=g,f=m,l=h);for(k*=.5;k>.5;){var n,o,p,q,r,s;(p=f-k)>=0&&(r=d(n=i.getPointAtLength(p)))<l?(e=n,f=p,l=r):(q=f+k)<=j&&(s=d(o=i.getPointAtLength(q)))<l?(e=o,f=q,l=s):k*=.5}return e={x:e.x,y:e.y,length:f,distance:Math.sqrt(l)}},c.is=e,c.snapTo=function(a,b,c){if(c=e(c,"finite")?c:10,e(a,"array")){for(var d=a.length;d--;)if(G(a[d]-b)<=c)return a[d]}else{a=+a;var f=b%a;if(c>f)return b-f;if(f>a-c)return b-f+a}return b},c.getRGB=i(function(a){if(!a||(a=A(a)).indexOf("-")+1)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};if("none"==a)return{r:-1,g:-1,b:-1,hex:"none",toString:Z};if(!(M[z](a.toLowerCase().substring(0,2))||"#"==a.charAt())&&(a=W(a)),!a)return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z};var b,d,f,g,h,i,j=a.match(K);return j?(j[2]&&(f=C(j[2].substring(5),16),d=C(j[2].substring(3,5),16),b=C(j[2].substring(1,3),16)),j[3]&&(f=C((h=j[3].charAt(3))+h,16),d=C((h=j[3].charAt(2))+h,16),b=C((h=j[3].charAt(1))+h,16)),j[4]&&(i=j[4].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b*=2.55),d=B(i[1]),"%"==i[1].slice(-1)&&(d*=2.55),f=B(i[2]),"%"==i[2].slice(-1)&&(f*=2.55),"rgba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100)),j[5]?(i=j[5].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsba"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsb2rgb(b,d,f,g)):j[6]?(i=j[6].split(L),b=B(i[0]),"%"==i[0].slice(-1)&&(b/=100),d=B(i[1]),"%"==i[1].slice(-1)&&(d/=100),f=B(i[2]),"%"==i[2].slice(-1)&&(f/=100),("deg"==i[0].slice(-3)||"°"==i[0].slice(-1))&&(b/=360),"hsla"==j[1].toLowerCase().slice(0,4)&&(g=B(i[3])),i[3]&&"%"==i[3].slice(-1)&&(g/=100),c.hsl2rgb(b,d,f,g)):(b=F(D.round(b),255),d=F(D.round(d),255),f=F(D.round(f),255),g=F(E(g,0),1),j={r:b,g:d,b:f,toString:Z},j.hex="#"+(16777216|f|d<<8|b<<16).toString(16).slice(1),j.opacity=e(g,"finite")?g:1,j)):{r:-1,g:-1,b:-1,hex:"none",error:1,toString:Z}},c),c.hsb=i(function(a,b,d){return c.hsb2rgb(a,b,d).hex}),c.hsl=i(function(a,b,d){return c.hsl2rgb(a,b,d).hex}),c.rgb=i(function(a,b,c,d){if(e(d,"finite")){var f=D.round;return"rgba("+[f(a),f(b),f(c),+d.toFixed(2)]+")"}return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)});var W=function(a){var b=y.doc.getElementsByTagName("head")[0]||y.doc.getElementsByTagName("svg")[0],c="rgb(255, 0, 0)";return(W=i(function(a){if("red"==a.toLowerCase())return c;b.style.color=c,b.style.color=a;var d=y.doc.defaultView.getComputedStyle(b,I).getPropertyValue("color");return d==c?null:d}))(a)},X=function(){return"hsb("+[this.h,this.s,this.b]+")"},Y=function(){return"hsl("+[this.h,this.s,this.l]+")"},Z=function(){return 1==this.opacity||null==this.opacity?this.hex:"rgba("+[this.r,this.g,this.b,this.opacity]+")"},$=function(a,b,d){if(null==b&&e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&(d=a.b,b=a.g,a=a.r),null==b&&e(a,string)){var f=c.getRGB(a);a=f.r,b=f.g,d=f.b}return(a>1||b>1||d>1)&&(a/=255,b/=255,d/=255),[a,b,d]},_=function(a,b,d,f){a=D.round(255*a),b=D.round(255*b),d=D.round(255*d);var g={r:a,g:b,b:d,opacity:e(f,"finite")?f:1,hex:c.rgb(a,b,d),toString:Z};return e(f,"finite")&&(g.opacity=f),g};c.color=function(a){var b;return e(a,"object")&&"h"in a&&"s"in a&&"b"in a?(b=c.hsb2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):e(a,"object")&&"h"in a&&"s"in a&&"l"in a?(b=c.hsl2rgb(a),a.r=b.r,a.g=b.g,a.b=b.b,a.opacity=1,a.hex=b.hex):(e(a,"string")&&(a=c.getRGB(a)),e(a,"object")&&"r"in a&&"g"in a&&"b"in a&&!("error"in a)?(b=c.rgb2hsl(a),a.h=b.h,a.s=b.s,a.l=b.l,b=c.rgb2hsb(a),a.v=b.b):(a={hex:"none"},a.r=a.g=a.b=a.h=a.s=a.v=a.l=-1,a.error=1)),a.toString=Z,a},c.hsb2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,d=a.o,a=a.h),a*=360;var f,g,h,i,j;return a=a%360/60,j=c*b,i=j*(1-G(a%2-1)),f=g=h=c-j,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.hsl2rgb=function(a,b,c,d){e(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h),(a>1||b>1||c>1)&&(a/=360,b/=100,c/=100),a*=360;var f,g,h,i,j;return a=a%360/60,j=2*b*(.5>c?c:1-c),i=j*(1-G(a%2-1)),f=g=h=c-j/2,a=~~a,f+=[j,i,0,0,i,j][a],g+=[i,j,j,i,0,0][a],h+=[0,0,i,j,j,i][a],_(f,g,h,d)},c.rgb2hsb=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;return f=E(a,b,c),g=f-F(a,b,c),d=0==g?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=0==g?0:g/f,{h:d,s:e,b:f,toString:X}},c.rgb2hsl=function(a,b,c){c=$(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;return g=E(a,b,c),h=F(a,b,c),i=g-h,d=0==i?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=0==i?0:.5>f?i/(2*f):i/(2-2*f),{h:d,s:e,l:f,toString:Y}},c.parsePathString=function(a){if(!a)return null;var b=c.path(a);if(b.arr)return c.path.clone(b.arr);var d={a:7,c:6,o:2,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,u:3,z:0},f=[];return e(a,"array")&&e(a[0],"array")&&(f=c.path.clone(a)),f.length||A(a).replace(N,function(a,b,c){var e=[],g=b.toLowerCase();if(c.replace(P,function(a,b){b&&e.push(+b)}),"m"==g&&e.length>2&&(f.push([b].concat(e.splice(0,2))),g="l",b="m"==b?"l":"L"),"o"==g&&1==e.length&&f.push([b,e[0]]),"r"==g)f.push([b].concat(e));else for(;e.length>=d[g]&&(f.push([b].concat(e.splice(0,d[g]))),d[g]););}),f.toString=c.path.toString,b.arr=c.path.clone(f),f};var ab=c.parseTransformString=function(a){if(!a)return null;var b=[];return e(a,"array")&&e(a[0],"array")&&(b=c.path.clone(a)),b.length||A(a).replace(O,function(a,c,d){{var e=[];c.toLowerCase()}d.replace(P,function(a,b){b&&e.push(+b)}),b.push([c].concat(e))}),b.toString=c.path.toString,b};c._.svgTransform2string=m,c._.rgTransform=/^[a-z][\s]*-?\.?\d/i,c._.transform2matrix=n,c._unit2px=q;y.doc.contains||y.doc.compareDocumentPosition?function(a,b){var c=9==a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a==d||!(!d||1!=d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)for(;b;)if(b=b.parentNode,b==a)return!0;return!1};c._.getSomeDefs=o,c._.getSomeSVG=p,c.select=function(a){return a=A(a).replace(/([^\\]):/g,"$1\\:"),w(y.doc.querySelector(a))},c.selectAll=function(a){for(var b=y.doc.querySelectorAll(a),d=(c.set||Array)(),e=0;e<b.length;e++)d.push(w(b[e]));return d},setInterval(function(){for(var a in V)if(V[z](a)){var b=V[a],c=b.node;("svg"!=b.type&&!c.ownerSVGElement||"svg"==b.type&&(!c.parentNode||"ownerSVGElement"in c.parentNode&&!c.ownerSVGElement))&&delete V[a]}},1e4),s.prototype.attr=function(a,c){var d=this,f=d.node;if(!a){if(1!=f.nodeType)return{text:f.nodeValue};for(var g=f.attributes,h={},i=0,j=g.length;j>i;i++)h[g[i].nodeName]=g[i].nodeValue;return h}if(e(a,"string")){if(!(arguments.length>1))return b("snap.util.getattr."+a,d).firstDefined();var k={};k[a]=c,a=k}for(var l in a)a[z](l)&&b("snap.util.attr."+l,d,a[l]);return d},c.parse=function(a){var b=y.doc.createDocumentFragment(),c=!0,d=y.doc.createElement("div");if(a=A(a),a.match(/^\s*<\s*svg(?:\s|>)/)||(a="<svg>"+a+"</svg>",c=!1),d.innerHTML=a,a=d.getElementsByTagName("svg")[0])if(c)b=a;else for(;a.firstChild;)b.appendChild(a.firstChild);return new t(b)},c.fragment=function(){for(var a=Array.prototype.slice.call(arguments,0),b=y.doc.createDocumentFragment(),d=0,e=a.length;e>d;d++){var f=a[d];f.node&&f.node.nodeType&&b.appendChild(f.node),f.nodeType&&b.appendChild(f),"string"==typeof f&&b.appendChild(c.parse(f).node)}return new t(b)},c._.make=u,c._.wrap=w,v.prototype.el=function(a,b){var c=u(a,this.node);return b&&c.attr(b),c},s.prototype.children=function(){for(var a=[],b=this.node.childNodes,d=0,e=b.length;e>d;d++)a[d]=c(b[d]);return a},s.prototype.toJSON=function(){var a=[];return x([this],a),a[0]},b.on("snap.util.getattr",function(){var a=b.nt();a=a.substring(a.lastIndexOf(".")+1);var c=a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});return bb[z](c)?this.node.ownerDocument.defaultView.getComputedStyle(this.node,null).getPropertyValue(c):d(this.node,a)});var bb={"alignment-baseline":0,"baseline-shift":0,clip:0,"clip-path":0,"clip-rule":0,color:0,"color-interpolation":0,"color-interpolation-filters":0,"color-profile":0,"color-rendering":0,cursor:0,direction:0,display:0,"dominant-baseline":0,"enable-background":0,fill:0,"fill-opacity":0,"fill-rule":0,filter:0,"flood-color":0,"flood-opacity":0,font:0,"font-family":0,"font-size":0,"font-size-adjust":0,"font-stretch":0,"font-style":0,"font-variant":0,"font-weight":0,"glyph-orientation-horizontal":0,"glyph-orientation-vertical":0,"image-rendering":0,kerning:0,"letter-spacing":0,"lighting-color":0,marker:0,"marker-end":0,"marker-mid":0,"marker-start":0,mask:0,opacity:0,overflow:0,"pointer-events":0,"shape-rendering":0,"stop-color":0,"stop-opacity":0,stroke:0,"stroke-dasharray":0,"stroke-dashoffset":0,"stroke-linecap":0,"stroke-linejoin":0,"stroke-miterlimit":0,"stroke-opacity":0,"stroke-width":0,"text-anchor":0,"text-decoration":0,"text-rendering":0,"unicode-bidi":0,visibility:0,"word-spacing":0,"writing-mode":0};b.on("snap.util.attr",function(a){var c=b.nt(),e={};c=c.substring(c.lastIndexOf(".")+1),e[c]=a;var f=c.replace(/-(\w)/gi,function(a,b){return b.toUpperCase()}),g=c.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()});bb[z](g)?this.node.style[f]=null==a?I:a:d(this.node,e)}),function(){}(v.prototype),c.ajax=function(a,c,d,f){var g=new XMLHttpRequest,h=S();if(g){if(e(c,"function"))f=d,d=c,c=null;else if(e(c,"object")){var i=[];for(var j in c)c.hasOwnProperty(j)&&i.push(encodeURIComponent(j)+"="+encodeURIComponent(c[j]));c=i.join("&")}return g.open(c?"POST":"GET",a,!0),c&&(g.setRequestHeader("X-Requested-With","XMLHttpRequest"),g.setRequestHeader("Content-type","application/x-www-form-urlencoded")),d&&(b.once("snap.ajax."+h+".0",d),b.once("snap.ajax."+h+".200",d),b.once("snap.ajax."+h+".304",d)),g.onreadystatechange=function(){4==g.readyState&&b("snap.ajax."+h+"."+g.status,f,g)},4==g.readyState?g:(g.send(c),g)}},c.load=function(a,b,d){c.ajax(a,function(a){var e=c.parse(a.responseText);d?b.call(d,e):b(e)})};var cb=function(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.body,e=c.documentElement,f=e.clientTop||d.clientTop||0,h=e.clientLeft||d.clientLeft||0,i=b.top+(g.win.pageYOffset||e.scrollTop||d.scrollTop)-f,j=b.left+(g.win.pageXOffset||e.scrollLeft||d.scrollLeft)-h;return{y:i,x:j}};return c.getElementByPoint=function(a,b){var c=this,d=(c.canvas,y.doc.elementFromPoint(a,b));if(y.win.opera&&"svg"==d.tagName){var e=cb(d),f=d.createSVGRect();f.x=a-e.x,f.y=b-e.y,f.width=f.height=1;var g=d.getIntersectionList(f,null);g.length&&(d=g[g.length-1])}return d?w(d):null},c.plugin=function(a){a(c,s,v,y,t)},y.win.Snap=c,c}(a||this);return d.plugin(function(d,e,f,g,h){function i(a,b){if(null==b){var c=!0;if(b=a.node.getAttribute("linearGradient"==a.type||"radialGradient"==a.type?"gradientTransform":"pattern"==a.type?"patternTransform":"transform"),!b)return new d.Matrix;b=d._.svgTransform2string(b)}else b=d._.rgTransform.test(b)?o(b).replace(/\.{3}|\u2026/g,a._.transform||""):d._.svgTransform2string(b),n(b,"array")&&(b=d.path?d.path.toString.call(b):o(b)),a._.transform=b;var e=d._.transform2matrix(b,a.getBBox(1));return c?e:void(a.matrix=e)}function j(a){function b(a,b){var c=q(a.node,b);c=c&&c.match(f),c=c&&c[2],c&&"#"==c.charAt()&&(c=c.substring(1),c&&(h[c]=(h[c]||[]).concat(function(c){var d={};d[b]=URL(c),q(a.node,d)})))}function c(a){var b=q(a.node,"xlink:href");b&&"#"==b.charAt()&&(b=b.substring(1),b&&(h[b]=(h[b]||[]).concat(function(b){a.attr("xlink:href","#"+b)})))}for(var d,e=a.selectAll("*"),f=/^\s*url\(("|'|)(.*)\1\)\s*$/,g=[],h={},i=0,j=e.length;j>i;i++){d=e[i],b(d,"fill"),b(d,"stroke"),b(d,"filter"),b(d,"mask"),b(d,"clip-path"),c(d);var k=q(d.node,"id");k&&(q(d.node,{id:d.id}),g.push({old:k,id:d.id}))}for(i=0,j=g.length;j>i;i++){var l=h[g[i].old];if(l)for(var m=0,n=l.length;n>m;m++)l[m](g[i].id)}}function k(a,b,c){return function(d){var e=d.slice(a,b);return 1==e.length&&(e=e[0]),c?c(e):e}}function l(a){return function(){var b=a?"<"+this.type:"",c=this.node.attributes,d=this.node.childNodes;if(a)for(var e=0,f=c.length;f>e;e++)b+=" "+c[e].name+'="'+c[e].value.replace(/"/g,'\\"')+'"';if(d.length){for(a&&(b+=">"),e=0,f=d.length;f>e;e++)3==d[e].nodeType?b+=d[e].nodeValue:1==d[e].nodeType&&(b+=u(d[e]).toString());a&&(b+="</"+this.type+">")}else a&&(b+="/>");return b}}var m=e.prototype,n=d.is,o=String,p=d._unit2px,q=d._.$,r=d._.make,s=d._.getSomeDefs,t="hasOwnProperty",u=d._.wrap;m.getBBox=function(a){if(!d.Matrix||!d.path)return this.node.getBBox();var b=this,c=new d.Matrix;if(b.removed)return d._.box();for(;"use"==b.type;)if(a||(c=c.add(b.transform().localMatrix.translate(b.attr("x")||0,b.attr("y")||0))),b.original)b=b.original;else{var e=b.attr("xlink:href");b=b.original=b.node.ownerDocument.getElementById(e.substring(e.indexOf("#")+1))}var f=b._,g=d.path.get[b.type]||d.path.get.deflt;try{return a?(f.bboxwt=g?d.path.getBBox(b.realPath=g(b)):d._.box(b.node.getBBox()),d._.box(f.bboxwt)):(b.realPath=g(b),b.matrix=b.transform().localMatrix,f.bbox=d.path.getBBox(d.path.map(b.realPath,c.add(b.matrix))),d._.box(f.bbox))}catch(h){return d._.box()}};var v=function(){return this.string};m.transform=function(a){var b=this._;if(null==a){for(var c,e=this,f=new d.Matrix(this.node.getCTM()),g=i(this),h=[g],j=new d.Matrix,k=g.toTransformString(),l=o(g)==o(this.matrix)?o(b.transform):k;"svg"!=e.type&&(e=e.parent());)h.push(i(e));for(c=h.length;c--;)j.add(h[c]);return{string:l,globalMatrix:f,totalMatrix:j,localMatrix:g,diffMatrix:f.clone().add(g.invert()),global:f.toTransformString(),total:j.toTransformString(),local:k,toString:v}}return a instanceof d.Matrix?(this.matrix=a,this._.transform=a.toTransformString()):i(this,a),this.node&&("linearGradient"==this.type||"radialGradient"==this.type?q(this.node,{gradientTransform:this.matrix}):"pattern"==this.type?q(this.node,{patternTransform:this.matrix}):q(this.node,{transform:this.matrix})),this},m.parent=function(){return u(this.node.parentNode)},m.append=m.add=function(a){if(a){if("set"==a.type){var b=this;return a.forEach(function(a){b.add(a)}),this}a=u(a),this.node.appendChild(a.node),a.paper=this.paper}return this},m.appendTo=function(a){return a&&(a=u(a),a.append(this)),this},m.prepend=function(a){if(a){if("set"==a.type){var b,c=this;return a.forEach(function(a){b?b.after(a):c.prepend(a),b=a}),this}a=u(a);var d=a.parent();this.node.insertBefore(a.node,this.node.firstChild),this.add&&this.add(),a.paper=this.paper,this.parent()&&this.parent().add(),d&&d.add()}return this},m.prependTo=function(a){return a=u(a),a.prepend(this),this},m.before=function(a){if("set"==a.type){var b=this;return a.forEach(function(a){var c=a.parent();b.node.parentNode.insertBefore(a.node,b.node),c&&c.add()}),this.parent().add(),this}a=u(a);var c=a.parent();return this.node.parentNode.insertBefore(a.node,this.node),this.parent()&&this.parent().add(),c&&c.add(),a.paper=this.paper,this},m.after=function(a){a=u(a);var b=a.parent();return this.node.nextSibling?this.node.parentNode.insertBefore(a.node,this.node.nextSibling):this.node.parentNode.appendChild(a.node),this.parent()&&this.parent().add(),b&&b.add(),a.paper=this.paper,this},m.insertBefore=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.insertAfter=function(a){a=u(a);var b=this.parent();return a.node.parentNode.insertBefore(this.node,a.node.nextSibling),this.paper=a.paper,b&&b.add(),a.parent()&&a.parent().add(),this},m.remove=function(){var a=this.parent();return this.node.parentNode&&this.node.parentNode.removeChild(this.node),delete this.paper,this.removed=!0,a&&a.add(),this},m.select=function(a){return u(this.node.querySelector(a))},m.selectAll=function(a){for(var b=this.node.querySelectorAll(a),c=(d.set||Array)(),e=0;e<b.length;e++)c.push(u(b[e]));return c},m.asPX=function(a,b){return null==b&&(b=this.attr(a)),+p(this,a,b)},m.use=function(){var a,b=this.node.id;return b||(b=this.id,q(this.node,{id:b})),a="linearGradient"==this.type||"radialGradient"==this.type||"pattern"==this.type?r(this.type,this.node.parentNode):r("use",this.node.parentNode),q(a.node,{"xlink:href":"#"+b}),a.original=this,a},m.clone=function(){var a=u(this.node.cloneNode(!0));return q(a.node,"id")&&q(a.node,{id:a.id}),j(a),a.insertAfter(this),a},m.toDefs=function(){var a=s(this);return a.appendChild(this.node),this},m.pattern=m.toPattern=function(a,b,c,d){var e=r("pattern",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,a=a.x),q(e.node,{x:a,y:b,width:c,height:d,patternUnits:"userSpaceOnUse",id:e.id,viewBox:[a,b,c,d].join(" ")}),e.node.appendChild(this.node),e},m.marker=function(a,b,c,d,e,f){var g=r("marker",s(this));return null==a&&(a=this.getBBox()),n(a,"object")&&"x"in a&&(b=a.y,c=a.width,d=a.height,e=a.refX||a.cx,f=a.refY||a.cy,a=a.x),q(g.node,{viewBox:[a,b,c,d].join(" "),markerWidth:c,markerHeight:d,orient:"auto",refX:e||0,refY:f||0,id:g.id}),g.node.appendChild(this.node),g};var w=function(a,b,d,e){"function"!=typeof d||d.length||(e=d,d=c.linear),this.attr=a,this.dur=b,d&&(this.easing=d),e&&(this.callback=e)};d._.Animation=w,d.animation=function(a,b,c,d){return new w(a,b,c,d)},m.inAnim=function(){var a=this,b=[];for(var c in a.anims)a.anims[t](c)&&!function(a){b.push({anim:new w(a._attrs,a.dur,a.easing,a._callback),mina:a,curStatus:a.status(),status:function(b){return a.status(b)},stop:function(){a.stop()}})}(a.anims[c]);return b},d.animate=function(a,d,e,f,g,h){"function"!=typeof g||g.length||(h=g,g=c.linear);var i=c.time(),j=c(a,d,i,i+f,c.time,e,g);return h&&b.once("mina.finish."+j.id,h),j},m.stop=function(){for(var a=this.inAnim(),b=0,c=a.length;c>b;b++)a[b].stop();return this},m.animate=function(a,d,e,f){"function"!=typeof e||e.length||(f=e,e=c.linear),a instanceof w&&(f=a.callback,e=a.easing,d=a.dur,a=a.attr);var g,h,i,j,l=[],m=[],p={},q=this;for(var r in a)if(a[t](r)){q.equal?(j=q.equal(r,o(a[r])),g=j.from,h=j.to,i=j.f):(g=+q.attr(r),h=+a[r]);var s=n(g,"array")?g.length:1;p[r]=k(l.length,l.length+s,i),l=l.concat(g),m=m.concat(h)}var u=c.time(),v=c(l,m,u,u+d,c.time,function(a){var b={};for(var c in p)p[t](c)&&(b[c]=p[c](a));q.attr(b)},e);return q.anims[v.id]=v,v._attrs=a,v._callback=f,b("snap.animcreated."+q.id,v),b.once("mina.finish."+v.id,function(){delete q.anims[v.id],f&&f.call(q)}),b.once("mina.stop."+v.id,function(){delete q.anims[v.id]}),q};var x={};m.data=function(a,c){var e=x[this.id]=x[this.id]||{};if(0==arguments.length)return b("snap.data.get."+this.id,this,e,null),e; +if(1==arguments.length){if(d.is(a,"object")){for(var f in a)a[t](f)&&this.data(f,a[f]);return this}return b("snap.data.get."+this.id,this,e[a],a),e[a]}return e[a]=c,b("snap.data.set."+this.id,this,c,a),this},m.removeData=function(a){return null==a?x[this.id]={}:x[this.id]&&delete x[this.id][a],this},m.outerSVG=m.toString=l(1),m.innerSVG=l(),m.toDataURL=function(){if(a&&a.btoa){var b=this.getBBox(),c=d.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>',{x:+b.x.toFixed(3),y:+b.y.toFixed(3),width:+b.width.toFixed(3),height:+b.height.toFixed(3),contents:this.outerSVG()});return"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(c)))}},h.prototype.select=m.select,h.prototype.selectAll=m.selectAll}),d.plugin(function(a){function b(a,b,d,e,f,g){return null==b&&"[object SVGMatrix]"==c.call(a)?(this.a=a.a,this.b=a.b,this.c=a.c,this.d=a.d,this.e=a.e,void(this.f=a.f)):void(null!=a?(this.a=+a,this.b=+b,this.c=+d,this.d=+e,this.e=+f,this.f=+g):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0))}var c=Object.prototype.toString,d=String,e=Math,f="";!function(c){function g(a){return a[0]*a[0]+a[1]*a[1]}function h(a){var b=e.sqrt(g(a));a[0]&&(a[0]/=b),a[1]&&(a[1]/=b)}c.add=function(a,c,d,e,f,g){var h,i,j,k,l=[[],[],[]],m=[[this.a,this.c,this.e],[this.b,this.d,this.f],[0,0,1]],n=[[a,d,f],[c,e,g],[0,0,1]];for(a&&a instanceof b&&(n=[[a.a,a.c,a.e],[a.b,a.d,a.f],[0,0,1]]),h=0;3>h;h++)for(i=0;3>i;i++){for(k=0,j=0;3>j;j++)k+=m[h][j]*n[j][i];l[h][i]=k}return this.a=l[0][0],this.b=l[1][0],this.c=l[0][1],this.d=l[1][1],this.e=l[0][2],this.f=l[1][2],this},c.invert=function(){var a=this,c=a.a*a.d-a.b*a.c;return new b(a.d/c,-a.b/c,-a.c/c,a.a/c,(a.c*a.f-a.d*a.e)/c,(a.b*a.e-a.a*a.f)/c)},c.clone=function(){return new b(this.a,this.b,this.c,this.d,this.e,this.f)},c.translate=function(a,b){return this.add(1,0,0,1,a,b)},c.scale=function(a,b,c,d){return null==b&&(b=a),(c||d)&&this.add(1,0,0,1,c,d),this.add(a,0,0,b,0,0),(c||d)&&this.add(1,0,0,1,-c,-d),this},c.rotate=function(b,c,d){b=a.rad(b),c=c||0,d=d||0;var f=+e.cos(b).toFixed(9),g=+e.sin(b).toFixed(9);return this.add(f,g,-g,f,c,d),this.add(1,0,0,1,-c,-d)},c.x=function(a,b){return a*this.a+b*this.c+this.e},c.y=function(a,b){return a*this.b+b*this.d+this.f},c.get=function(a){return+this[d.fromCharCode(97+a)].toFixed(4)},c.toString=function(){return"matrix("+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)].join()+")"},c.offset=function(){return[this.e.toFixed(4),this.f.toFixed(4)]},c.determinant=function(){return this.a*this.d-this.b*this.c},c.split=function(){var b={};b.dx=this.e,b.dy=this.f;var c=[[this.a,this.c],[this.b,this.d]];b.scalex=e.sqrt(g(c[0])),h(c[0]),b.shear=c[0][0]*c[1][0]+c[0][1]*c[1][1],c[1]=[c[1][0]-c[0][0]*b.shear,c[1][1]-c[0][1]*b.shear],b.scaley=e.sqrt(g(c[1])),h(c[1]),b.shear/=b.scaley,this.determinant()<0&&(b.scalex=-b.scalex);var d=-c[0][1],f=c[1][1];return 0>f?(b.rotate=a.deg(e.acos(f)),0>d&&(b.rotate=360-b.rotate)):b.rotate=a.deg(e.asin(d)),b.isSimple=!(+b.shear.toFixed(9)||b.scalex.toFixed(9)!=b.scaley.toFixed(9)&&b.rotate),b.isSuperSimple=!+b.shear.toFixed(9)&&b.scalex.toFixed(9)==b.scaley.toFixed(9)&&!b.rotate,b.noRotation=!+b.shear.toFixed(9)&&!b.rotate,b},c.toTransformString=function(a){var b=a||this.split();return+b.shear.toFixed(9)?"m"+[this.get(0),this.get(1),this.get(2),this.get(3),this.get(4),this.get(5)]:(b.scalex=+b.scalex.toFixed(4),b.scaley=+b.scaley.toFixed(4),b.rotate=+b.rotate.toFixed(4),(b.dx||b.dy?"t"+[+b.dx.toFixed(4),+b.dy.toFixed(4)]:f)+(1!=b.scalex||1!=b.scaley?"s"+[b.scalex,b.scaley,0,0]:f)+(b.rotate?"r"+[+b.rotate.toFixed(4),0,0]:f))}}(b.prototype),a.Matrix=b,a.matrix=function(a,c,d,e,f,g){return new b(a,c,d,e,f,g)}}),d.plugin(function(a,c,d,e,f){function g(d){return function(e){if(b.stop(),e instanceof f&&1==e.node.childNodes.length&&("radialGradient"==e.node.firstChild.tagName||"linearGradient"==e.node.firstChild.tagName||"pattern"==e.node.firstChild.tagName)&&(e=e.node.firstChild,n(this).appendChild(e),e=l(e)),e instanceof c)if("radialGradient"==e.type||"linearGradient"==e.type||"pattern"==e.type){e.node.id||p(e.node,{id:e.id});var g=q(e.node.id)}else g=e.attr(d);else if(g=a.color(e),g.error){var h=a(n(this).ownerSVGElement).gradient(e);h?(h.node.id||p(h.node,{id:h.id}),g=q(h.node.id)):g=e}else g=r(g);var i={};i[d]=g,p(this.node,i),this.node.style[d]=t}}function h(a){b.stop(),a==+a&&(a+="px"),this.node.style.fontSize=a}function i(a){for(var b=[],c=a.childNodes,d=0,e=c.length;e>d;d++){var f=c[d];3==f.nodeType&&b.push(f.nodeValue),"tspan"==f.tagName&&b.push(1==f.childNodes.length&&3==f.firstChild.nodeType?f.firstChild.nodeValue:i(f))}return b}function j(){return b.stop(),this.node.style.fontSize}var k=a._.make,l=a._.wrap,m=a.is,n=a._.getSomeDefs,o=/^url\(#?([^)]+)\)$/,p=a._.$,q=a.url,r=String,s=a._.separator,t="";b.on("snap.util.attr.mask",function(a){if(a instanceof c||a instanceof f){if(b.stop(),a instanceof f&&1==a.node.childNodes.length&&(a=a.node.firstChild,n(this).appendChild(a),a=l(a)),"mask"==a.type)var d=a;else d=k("mask",n(this)),d.node.appendChild(a.node);!d.node.id&&p(d.node,{id:d.id}),p(this.node,{mask:q(d.id)})}}),function(a){b.on("snap.util.attr.clip",a),b.on("snap.util.attr.clip-path",a),b.on("snap.util.attr.clipPath",a)}(function(a){if(a instanceof c||a instanceof f){if(b.stop(),"clipPath"==a.type)var d=a;else d=k("clipPath",n(this)),d.node.appendChild(a.node),!d.node.id&&p(d.node,{id:d.id});p(this.node,{"clip-path":q(d.node.id||d.id)})}}),b.on("snap.util.attr.fill",g("fill")),b.on("snap.util.attr.stroke",g("stroke"));var u=/^([lr])(?:\(([^)]*)\))?(.*)$/i;b.on("snap.util.grad.parse",function(a){a=r(a);var b=a.match(u);if(!b)return null;var c=b[1],d=b[2],e=b[3];return d=d.split(/\s*,\s*/).map(function(a){return+a==a?+a:a}),1==d.length&&0==d[0]&&(d=[]),e=e.split("-"),e=e.map(function(a){a=a.split(":");var b={color:a[0]};return a[1]&&(b.offset=parseFloat(a[1])),b}),{type:c,params:d,stops:e}}),b.on("snap.util.attr.d",function(c){b.stop(),m(c,"array")&&m(c[0],"array")&&(c=a.path.toString.call(c)),c=r(c),c.match(/[ruo]/i)&&(c=a.path.toAbsolute(c)),p(this.node,{d:c})})(-1),b.on("snap.util.attr.#text",function(a){b.stop(),a=r(a);for(var c=e.doc.createTextNode(a);this.node.firstChild;)this.node.removeChild(this.node.firstChild);this.node.appendChild(c)})(-1),b.on("snap.util.attr.path",function(a){b.stop(),this.attr({d:a})})(-1),b.on("snap.util.attr.class",function(a){b.stop(),this.node.className.baseVal=a})(-1),b.on("snap.util.attr.viewBox",function(a){var c;c=m(a,"object")&&"x"in a?[a.x,a.y,a.width,a.height].join(" "):m(a,"array")?a.join(" "):a,p(this.node,{viewBox:c}),b.stop()})(-1),b.on("snap.util.attr.transform",function(a){this.transform(a),b.stop()})(-1),b.on("snap.util.attr.r",function(a){"rect"==this.type&&(b.stop(),p(this.node,{rx:a,ry:a}))})(-1),b.on("snap.util.attr.textpath",function(a){if(b.stop(),"text"==this.type){var d,e,f;if(!a&&this.textPath){for(e=this.textPath;e.node.firstChild;)this.node.appendChild(e.node.firstChild);return e.remove(),void delete this.textPath}if(m(a,"string")){var g=n(this),h=l(g.parentNode).path(a);g.appendChild(h.node),d=h.id,h.attr({id:d})}else a=l(a),a instanceof c&&(d=a.attr("id"),d||(d=a.id,a.attr({id:d})));if(d)if(e=this.textPath,f=this.node,e)e.attr({"xlink:href":"#"+d});else{for(e=p("textPath",{"xlink:href":"#"+d});f.firstChild;)e.appendChild(f.firstChild);f.appendChild(e),this.textPath=l(e)}}})(-1),b.on("snap.util.attr.text",function(a){if("text"==this.type){for(var c=this.node,d=function(a){var b=p("tspan");if(m(a,"array"))for(var c=0;c<a.length;c++)b.appendChild(d(a[c]));else b.appendChild(e.doc.createTextNode(a));return b.normalize&&b.normalize(),b};c.firstChild;)c.removeChild(c.firstChild);for(var f=d(a);f.firstChild;)c.appendChild(f.firstChild)}b.stop()})(-1),b.on("snap.util.attr.fontSize",h)(-1),b.on("snap.util.attr.font-size",h)(-1),b.on("snap.util.getattr.transform",function(){return b.stop(),this.transform()})(-1),b.on("snap.util.getattr.textpath",function(){return b.stop(),this.textPath})(-1),function(){function c(c){return function(){b.stop();var d=e.doc.defaultView.getComputedStyle(this.node,null).getPropertyValue("marker-"+c);return"none"==d?d:a(e.doc.getElementById(d.match(o)[1]))}}function d(a){return function(c){b.stop();var d="marker"+a.charAt(0).toUpperCase()+a.substring(1);if(""==c||!c)return void(this.node.style[d]="none");if("marker"==c.type){var e=c.node.id;return e||p(c.node,{id:c.id}),void(this.node.style[d]=q(e))}}}b.on("snap.util.getattr.marker-end",c("end"))(-1),b.on("snap.util.getattr.markerEnd",c("end"))(-1),b.on("snap.util.getattr.marker-start",c("start"))(-1),b.on("snap.util.getattr.markerStart",c("start"))(-1),b.on("snap.util.getattr.marker-mid",c("mid"))(-1),b.on("snap.util.getattr.markerMid",c("mid"))(-1),b.on("snap.util.attr.marker-end",d("end"))(-1),b.on("snap.util.attr.markerEnd",d("end"))(-1),b.on("snap.util.attr.marker-start",d("start"))(-1),b.on("snap.util.attr.markerStart",d("start"))(-1),b.on("snap.util.attr.marker-mid",d("mid"))(-1),b.on("snap.util.attr.markerMid",d("mid"))(-1)}(),b.on("snap.util.getattr.r",function(){return"rect"==this.type&&p(this.node,"rx")==p(this.node,"ry")?(b.stop(),p(this.node,"rx")):void 0})(-1),b.on("snap.util.getattr.text",function(){if("text"==this.type||"tspan"==this.type){b.stop();var a=i(this.node);return 1==a.length?a[0]:a}})(-1),b.on("snap.util.getattr.#text",function(){return this.node.textContent})(-1),b.on("snap.util.getattr.viewBox",function(){b.stop();var c=p(this.node,"viewBox");return c?(c=c.split(s),a._.box(+c[0],+c[1],+c[2],+c[3])):void 0})(-1),b.on("snap.util.getattr.points",function(){var a=p(this.node,"points");return b.stop(),a?a.split(s):void 0})(-1),b.on("snap.util.getattr.path",function(){var a=p(this.node,"d");return b.stop(),a})(-1),b.on("snap.util.getattr.class",function(){return this.node.className.baseVal})(-1),b.on("snap.util.getattr.fontSize",j)(-1),b.on("snap.util.getattr.font-size",j)(-1)}),d.plugin(function(a,b){var c=/\S+/g,d=String,e=b.prototype;e.addClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(h.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e||k.push(f);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.removeClass=function(a){var b,e,f,g,h=d(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];if(k.length){for(b=0;f=h[b++];)e=k.indexOf(f),~e&&k.splice(e,1);g=k.join(" "),j!=g&&(i.className.baseVal=g)}return this},e.hasClass=function(a){var b=this.node,d=b.className.baseVal,e=d.match(c)||[];return!!~e.indexOf(a)},e.toggleClass=function(a,b){if(null!=b)return b?this.addClass(a):this.removeClass(a);var d,e,f,g,h=(a||"").match(c)||[],i=this.node,j=i.className.baseVal,k=j.match(c)||[];for(d=0;f=h[d++];)e=k.indexOf(f),~e?k.splice(e,1):k.push(f);return g=k.join(" "),j!=g&&(i.className.baseVal=g),this}}),d.plugin(function(){function a(a){return a}function c(a){return function(b){return+b.toFixed(3)+a}}var d={"+":function(a,b){return a+b},"-":function(a,b){return a-b},"/":function(a,b){return a/b},"*":function(a,b){return a*b}},e=String,f=/[a-z]+$/i,g=/^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/;b.on("snap.util.attr",function(a){var c=e(a).match(g);if(c){var h=b.nt(),i=h.substring(h.lastIndexOf(".")+1),j=this.attr(i),k={};b.stop();var l=c[3]||"",m=j.match(f),n=d[c[1]];if(m&&m==l?a=n(parseFloat(j),+c[2]):(j=this.asPX(i),a=n(this.asPX(i),this.asPX(i,c[2]+l))),isNaN(j)||isNaN(a))return;k[i]=a,this.attr(k)}})(-10),b.on("snap.util.equal",function(h,i){var j=e(this.attr(h)||""),k=e(i).match(g);if(k){b.stop();var l=k[3]||"",m=j.match(f),n=d[k[1]];return m&&m==l?{from:parseFloat(j),to:n(parseFloat(j),+k[2]),f:c(m)}:(j=this.asPX(h),{from:j,to:n(j,this.asPX(h,k[2]+l)),f:a})}})(-10)}),d.plugin(function(c,d,e,f){var g=e.prototype,h=c.is;g.rect=function(a,b,c,d,e,f){var g;return null==f&&(f=e),h(a,"object")&&"[object Object]"==a?g=a:null!=a&&(g={x:a,y:b,width:c,height:d},null!=e&&(g.rx=e,g.ry=f)),this.el("rect",g)},g.circle=function(a,b,c){var d;return h(a,"object")&&"[object Object]"==a?d=a:null!=a&&(d={cx:a,cy:b,r:c}),this.el("circle",d)};var i=function(){function a(){this.parentNode.removeChild(this)}return function(b,c){var d=f.doc.createElement("img"),e=f.doc.body;d.style.cssText="position:absolute;left:-9999em;top:-9999em",d.onload=function(){c.call(d),d.onload=d.onerror=null,e.removeChild(d)},d.onerror=a,e.appendChild(d),d.src=b}}();g.image=function(a,b,d,e,f){var g=this.el("image");if(h(a,"object")&&"src"in a)g.attr(a);else if(null!=a){var j={"xlink:href":a,preserveAspectRatio:"none"};null!=b&&null!=d&&(j.x=b,j.y=d),null!=e&&null!=f?(j.width=e,j.height=f):i(a,function(){c._.$(g.node,{width:this.offsetWidth,height:this.offsetHeight})}),c._.$(g.node,j)}return g},g.ellipse=function(a,b,c,d){var e;return h(a,"object")&&"[object Object]"==a?e=a:null!=a&&(e={cx:a,cy:b,rx:c,ry:d}),this.el("ellipse",e)},g.path=function(a){var b;return h(a,"object")&&!h(a,"array")?b=a:a&&(b={d:a}),this.el("path",b)},g.group=g.g=function(a){var b=this.el("g");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.svg=function(a,b,c,d,e,f,g,i){var j={};return h(a,"object")&&null==b?j=a:(null!=a&&(j.x=a),null!=b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),null!=e&&null!=f&&null!=g&&null!=i&&(j.viewBox=[e,f,g,i])),this.el("svg",j)},g.mask=function(a){var b=this.el("mask");return 1==arguments.length&&a&&!a.type?b.attr(a):arguments.length&&b.add(Array.prototype.slice.call(arguments,0)),b},g.ptrn=function(a,b,c,d,e,f,g,i){if(h(a,"object"))var j=a;else j={patternUnits:"userSpaceOnUse"},a&&(j.x=a),b&&(j.y=b),null!=c&&(j.width=c),null!=d&&(j.height=d),j.viewBox=null!=e&&null!=f&&null!=g&&null!=i?[e,f,g,i]:[a||0,b||0,c||0,d||0];return this.el("pattern",j)},g.use=function(a){return null!=a?(a instanceof d&&(a.attr("id")||a.attr({id:c._.id(a)}),a=a.attr("id")),"#"==String(a).charAt()&&(a=a.substring(1)),this.el("use",{"xlink:href":"#"+a})):d.prototype.use.call(this)},g.symbol=function(a,b,c,d){var e={};return null!=a&&null!=b&&null!=c&&null!=d&&(e.viewBox=[a,b,c,d]),this.el("symbol",e)},g.text=function(a,b,c){var d={};return h(a,"object")?d=a:null!=a&&(d={x:a,y:b,text:c||""}),this.el("text",d)},g.line=function(a,b,c,d){var e={};return h(a,"object")?e=a:null!=a&&(e={x1:a,x2:c,y1:b,y2:d}),this.el("line",e)},g.polyline=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polyline",b)},g.polygon=function(a){arguments.length>1&&(a=Array.prototype.slice.call(arguments,0));var b={};return h(a,"object")&&!h(a,"array")?b=a:null!=a&&(b={points:a}),this.el("polygon",b)},function(){function d(){return this.selectAll("stop")}function e(a,b){var d=k("stop"),e={offset:+b+"%"};return a=c.color(a),e["stop-color"]=a.hex,a.opacity<1&&(e["stop-opacity"]=a.opacity),k(d,e),this.node.appendChild(d),this}function f(){if("linearGradient"==this.type){var a=k(this.node,"x1")||0,b=k(this.node,"x2")||1,d=k(this.node,"y1")||0,e=k(this.node,"y2")||0;return c._.box(a,d,math.abs(b-a),math.abs(e-d))}var f=this.node.cx||.5,g=this.node.cy||.5,h=this.node.r||0;return c._.box(f-h,g-h,2*h,2*h)}function h(a,c){function d(a,b){for(var c=(b-l)/(a-m),d=m;a>d;d++)g[d].offset=+(+l+c*(d-m)).toFixed(2);m=a,l=b}var e,f=b("snap.util.grad.parse",null,c).firstDefined();if(!f)return null;f.params.unshift(a),e="l"==f.type.toLowerCase()?i.apply(0,f.params):j.apply(0,f.params),f.type!=f.type.toLowerCase()&&k(e.node,{gradientUnits:"userSpaceOnUse"});var g=f.stops,h=g.length,l=0,m=0;h--;for(var n=0;h>n;n++)"offset"in g[n]&&d(n,g[n].offset);for(g[h].offset=g[h].offset||100,d(h,g[h].offset),n=0;h>=n;n++){var o=g[n];e.addStop(o.color,o.offset)}return e}function i(a,b,g,h,i){var j=c._.make("linearGradient",a);return j.stops=d,j.addStop=e,j.getBBox=f,null!=b&&k(j.node,{x1:b,y1:g,x2:h,y2:i}),j}function j(a,b,g,h,i,j){var l=c._.make("radialGradient",a);return l.stops=d,l.addStop=e,l.getBBox=f,null!=b&&k(l.node,{cx:b,cy:g,r:h}),null!=i&&null!=j&&k(l.node,{fx:i,fy:j}),l}var k=c._.$;g.gradient=function(a){return h(this.defs,a)},g.gradientLinear=function(a,b,c,d){return i(this.defs,a,b,c,d)},g.gradientRadial=function(a,b,c,d,e){return j(this.defs,a,b,c,d,e)},g.toString=function(){var a,b=this.node.ownerDocument,d=b.createDocumentFragment(),e=b.createElement("div"),f=this.node.cloneNode(!0);return d.appendChild(e),e.appendChild(f),c._.$(f,{xmlns:"http://www.w3.org/2000/svg"}),a=e.innerHTML,d.removeChild(d.firstChild),a},g.toDataURL=function(){return a&&a.btoa?"data:image/svg+xml;base64,"+btoa(unescape(encodeURIComponent(this))):void 0},g.clear=function(){for(var a,b=this.node.firstChild;b;)a=b.nextSibling,"defs"!=b.tagName?b.parentNode.removeChild(b):g.clear.call({node:b}),b=a}}()}),d.plugin(function(a,b){function c(a){var b=c.ps=c.ps||{};return b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[K](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])}),b[a]}function d(a,b,c,d){return null==a&&(a=b=c=d=0),null==b&&(b=a.y,c=a.width,d=a.height,a=a.x),{x:a,y:b,width:c,w:c,height:d,h:d,x2:a+c,y2:b+d,cx:a+c/2,cy:b+d/2,r1:N.min(c,d)/2,r2:N.max(c,d)/2,r0:N.sqrt(c*c+d*d)/2,path:w(a,b,c,d),vb:[a,b,c,d].join(" ")}}function e(){return this.join(",").replace(L,"$1")}function f(a){var b=J(a);return b.toString=e,b}function g(a,b,c,d,e,f,g,h,j){return null==j?n(a,b,c,d,e,f,g,h):i(a,b,c,d,e,f,g,h,o(a,b,c,d,e,f,g,h,j))}function h(c,d){function e(a){return+(+a).toFixed(3)}return a._.cacher(function(a,f,h){a instanceof b&&(a=a.attr("d")),a=E(a);for(var j,k,l,m,n,o="",p={},q=0,r=0,s=a.length;s>r;r++){if(l=a[r],"M"==l[0])j=+l[1],k=+l[2];else{if(m=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6]),q+m>f){if(d&&!p.start){if(n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q),o+=["C"+e(n.start.x),e(n.start.y),e(n.m.x),e(n.m.y),e(n.x),e(n.y)],h)return o;p.start=o,o=["M"+e(n.x),e(n.y)+"C"+e(n.n.x),e(n.n.y),e(n.end.x),e(n.end.y),e(l[5]),e(l[6])].join(),q+=m,j=+l[5],k=+l[6];continue}if(!c&&!d)return n=g(j,k,l[1],l[2],l[3],l[4],l[5],l[6],f-q)}q+=m,j=+l[5],k=+l[6]}o+=l.shift()+l}return p.end=o,n=c?q:d?p:i(j,k,l[0],l[1],l[2],l[3],l[4],l[5],1)},null,a._.clone)}function i(a,b,c,d,e,f,g,h,i){var j=1-i,k=R(j,3),l=R(j,2),m=i*i,n=m*i,o=k*a+3*l*i*c+3*j*i*i*e+n*g,p=k*b+3*l*i*d+3*j*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,w=j*e+i*g,x=j*f+i*h,y=90-180*N.atan2(q-s,r-t)/O;return{x:o,y:p,m:{x:q,y:r},n:{x:s,y:t},start:{x:u,y:v},end:{x:w,y:x},alpha:y}}function j(b,c,e,f,g,h,i,j){a.is(b,"array")||(b=[b,c,e,f,g,h,i,j]);var k=D.apply(null,b);return d(k.min.x,k.min.y,k.max.x-k.min.x,k.max.y-k.min.y)}function k(a,b,c){return b>=a.x&&b<=a.x+a.width&&c>=a.y&&c<=a.y+a.height}function l(a,b){return a=d(a),b=d(b),k(b,a.x,a.y)||k(b,a.x2,a.y)||k(b,a.x,a.y2)||k(b,a.x2,a.y2)||k(a,b.x,b.y)||k(a,b.x2,b.y)||k(a,b.x,b.y2)||k(a,b.x2,b.y2)||(a.x<b.x2&&a.x>b.x||b.x<a.x2&&b.x>a.x)&&(a.y<b.y2&&a.y>b.y||b.y<a.y2&&b.y>a.y)}function m(a,b,c,d,e){var f=-3*b+9*c-9*d+3*e,g=a*f+6*b-12*c+6*d;return a*g-3*b+3*c}function n(a,b,c,d,e,f,g,h,i){null==i&&(i=1),i=i>1?1:0>i?0:i;for(var j=i/2,k=12,l=[-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816],n=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],o=0,p=0;k>p;p++){var q=j*l[p]+j,r=m(q,a,c,e,g),s=m(q,b,d,f,h),t=r*r+s*s;o+=n[p]*N.sqrt(t)}return j*o}function o(a,b,c,d,e,f,g,h,i){if(!(0>i||n(a,b,c,d,e,f,g,h)<i)){var j,k=1,l=k/2,m=k-l,o=.01;for(j=n(a,b,c,d,e,f,g,h,m);S(j-i)>o;)l/=2,m+=(i>j?1:-1)*l,j=n(a,b,c,d,e,f,g,h,m);return m}}function p(a,b,c,d,e,f,g,h){if(!(Q(a,c)<P(e,g)||P(a,c)>Q(e,g)||Q(b,d)<P(f,h)||P(b,d)>Q(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(k){var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(!(n<+P(a,c).toFixed(2)||n>+Q(a,c).toFixed(2)||n<+P(e,g).toFixed(2)||n>+Q(e,g).toFixed(2)||o<+P(b,d).toFixed(2)||o>+Q(b,d).toFixed(2)||o<+P(f,h).toFixed(2)||o>+Q(f,h).toFixed(2)))return{x:l,y:m}}}}function q(a,b,c){var d=j(a),e=j(b);if(!l(d,e))return c?0:[];for(var f=n.apply(0,a),g=n.apply(0,b),h=~~(f/8),k=~~(g/8),m=[],o=[],q={},r=c?0:[],s=0;h+1>s;s++){var t=i.apply(0,a.concat(s/h));m.push({x:t.x,y:t.y,t:s/h})}for(s=0;k+1>s;s++)t=i.apply(0,b.concat(s/k)),o.push({x:t.x,y:t.y,t:s/k});for(s=0;h>s;s++)for(var u=0;k>u;u++){var v=m[s],w=m[s+1],x=o[u],y=o[u+1],z=S(w.x-v.x)<.001?"y":"x",A=S(y.x-x.x)<.001?"y":"x",B=p(v.x,v.y,w.x,w.y,x.x,x.y,y.x,y.y);if(B){if(q[B.x.toFixed(4)]==B.y.toFixed(4))continue;q[B.x.toFixed(4)]=B.y.toFixed(4);var C=v.t+S((B[z]-v[z])/(w[z]-v[z]))*(w.t-v.t),D=x.t+S((B[A]-x[A])/(y[A]-x[A]))*(y.t-x.t);C>=0&&1>=C&&D>=0&&1>=D&&(c?r++:r.push({x:B.x,y:B.y,t1:C,t2:D}))}}return r}function r(a,b){return t(a,b)}function s(a,b){return t(a,b,1)}function t(a,b,c){a=E(a),b=E(b);for(var d,e,f,g,h,i,j,k,l,m,n=c?0:[],o=0,p=a.length;p>o;o++){var r=a[o];if("M"==r[0])d=h=r[1],e=i=r[2];else{"C"==r[0]?(l=[d,e].concat(r.slice(1)),d=l[6],e=l[7]):(l=[d,e,d,e,h,i,h,i],d=h,e=i);for(var s=0,t=b.length;t>s;s++){var u=b[s];if("M"==u[0])f=j=u[1],g=k=u[2];else{"C"==u[0]?(m=[f,g].concat(u.slice(1)),f=m[6],g=m[7]):(m=[f,g,f,g,j,k,j,k],f=j,g=k);var v=q(l,m,c);if(c)n+=v;else{for(var w=0,x=v.length;x>w;w++)v[w].segment1=o,v[w].segment2=s,v[w].bez1=l,v[w].bez2=m;n=n.concat(v)}}}}}return n}function u(a,b,c){var d=v(a);return k(d,b,c)&&t(a,[["M",b,c],["H",d.x2+10]],1)%2==1}function v(a){var b=c(a);if(b.bbox)return J(b.bbox);if(!a)return d();a=E(a);for(var e,f=0,g=0,h=[],i=[],j=0,k=a.length;k>j;j++)if(e=a[j],"M"==e[0])f=e[1],g=e[2],h.push(f),i.push(g);else{var l=D(f,g,e[1],e[2],e[3],e[4],e[5],e[6]);h=h.concat(l.min.x,l.max.x),i=i.concat(l.min.y,l.max.y),f=e[5],g=e[6]}var m=P.apply(0,h),n=P.apply(0,i),o=Q.apply(0,h),p=Q.apply(0,i),q=d(m,n,o-m,p-n);return b.bbox=J(q),q}function w(a,b,c,d,f){if(f)return[["M",+a+ +f,b],["l",c-2*f,0],["a",f,f,0,0,1,f,f],["l",0,d-2*f],["a",f,f,0,0,1,-f,f],["l",2*f-c,0],["a",f,f,0,0,1,-f,-f],["l",0,2*f-d],["a",f,f,0,0,1,f,-f],["z"]];var g=[["M",a,b],["l",c,0],["l",0,d],["l",-c,0],["z"]];return g.toString=e,g}function x(a,b,c,d,f){if(null==f&&null==d&&(d=c),a=+a,b=+b,c=+c,d=+d,null!=f)var g=Math.PI/180,h=a+c*Math.cos(-d*g),i=a+c*Math.cos(-f*g),j=b+c*Math.sin(-d*g),k=b+c*Math.sin(-f*g),l=[["M",h,j],["A",c,c,0,+(f-d>180),0,i,k]];else l=[["M",a,b],["m",0,-d],["a",c,d,0,1,1,0,2*d],["a",c,d,0,1,1,0,-2*d],["z"]];return l.toString=e,l}function y(b){var d=c(b),g=String.prototype.toLowerCase;if(d.rel)return f(d.rel);a.is(b,"array")&&a.is(b&&b[0],"array")||(b=a.parsePathString(b));var h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=b[0][1],j=b[0][2],k=i,l=j,m++,h.push(["M",i,j]));for(var n=m,o=b.length;o>n;n++){var p=h[n]=[],q=b[n];if(q[0]!=g.call(q[0]))switch(p[0]=g.call(q[0]),p[0]){case"a":p[1]=q[1],p[2]=q[2],p[3]=q[3],p[4]=q[4],p[5]=q[5],p[6]=+(q[6]-i).toFixed(3),p[7]=+(q[7]-j).toFixed(3);break;case"v":p[1]=+(q[1]-j).toFixed(3);break;case"m":k=q[1],l=q[2];default:for(var r=1,s=q.length;s>r;r++)p[r]=+(q[r]-(r%2?i:j)).toFixed(3)}else{p=h[n]=[],"m"==q[0]&&(k=q[1]+i,l=q[2]+j);for(var t=0,u=q.length;u>t;t++)h[n][t]=q[t]}var v=h[n].length;switch(h[n][0]){case"z":i=k,j=l;break;case"h":i+=+h[n][v-1];break;case"v":j+=+h[n][v-1];break;default:i+=+h[n][v-2],j+=+h[n][v-1]}}return h.toString=e,d.rel=f(h),h}function z(b){var d=c(b);if(d.abs)return f(d.abs);if(I(b,"array")&&I(b&&b[0],"array")||(b=a.parsePathString(b)),!b||!b.length)return[["M",0,0]];var g,h=[],i=0,j=0,k=0,l=0,m=0;"M"==b[0][0]&&(i=+b[0][1],j=+b[0][2],k=i,l=j,m++,h[0]=["M",i,j]);for(var n,o,p=3==b.length&&"M"==b[0][0]&&"R"==b[1][0].toUpperCase()&&"Z"==b[2][0].toUpperCase(),q=m,r=b.length;r>q;q++){if(h.push(n=[]),o=b[q],g=o[0],g!=g.toUpperCase())switch(n[0]=g.toUpperCase(),n[0]){case"A":n[1]=o[1],n[2]=o[2],n[3]=o[3],n[4]=o[4],n[5]=o[5],n[6]=+o[6]+i,n[7]=+o[7]+j;break;case"V":n[1]=+o[1]+j;break;case"H":n[1]=+o[1]+i;break;case"R":for(var s=[i,j].concat(o.slice(1)),t=2,u=s.length;u>t;t++)s[t]=+s[t]+i,s[++t]=+s[t]+j;h.pop(),h=h.concat(G(s,p));break;case"O":h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);break;case"U":h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));break;case"M":k=+o[1]+i,l=+o[2]+j;default:for(t=1,u=o.length;u>t;t++)n[t]=+o[t]+(t%2?i:j)}else if("R"==g)s=[i,j].concat(o.slice(1)),h.pop(),h=h.concat(G(s,p)),n=["R"].concat(o.slice(-2));else if("O"==g)h.pop(),s=x(i,j,o[1],o[2]),s.push(s[0]),h=h.concat(s);else if("U"==g)h.pop(),h=h.concat(x(i,j,o[1],o[2],o[3])),n=["U"].concat(h[h.length-1].slice(-2));else for(var v=0,w=o.length;w>v;v++)n[v]=o[v];if(g=g.toUpperCase(),"O"!=g)switch(n[0]){case"Z":i=+k,j=+l;break;case"H":i=n[1];break;case"V":j=n[1];break;case"M":k=n[n.length-2],l=n[n.length-1];default:i=n[n.length-2],j=n[n.length-1]}}return h.toString=e,d.abs=f(h),h}function A(a,b,c,d){return[a,b,c,d,c,d]}function B(a,b,c,d,e,f){var g=1/3,h=2/3;return[g*a+h*c,g*b+h*d,g*e+h*c,g*f+h*d,e,f]}function C(b,c,d,e,f,g,h,i,j,k){var l,m=120*O/180,n=O/180*(+f||0),o=[],p=a._.cacher(function(a,b,c){var d=a*N.cos(c)-b*N.sin(c),e=a*N.sin(c)+b*N.cos(c);return{x:d,y:e}});if(k)y=k[0],z=k[1],w=k[2],x=k[3];else{l=p(b,c,-n),b=l.x,c=l.y,l=p(i,j,-n),i=l.x,j=l.y;var q=(N.cos(O/180*f),N.sin(O/180*f),(b-i)/2),r=(c-j)/2,s=q*q/(d*d)+r*r/(e*e);s>1&&(s=N.sqrt(s),d=s*d,e=s*e);var t=d*d,u=e*e,v=(g==h?-1:1)*N.sqrt(S((t*u-t*r*r-u*q*q)/(t*r*r+u*q*q))),w=v*d*r/e+(b+i)/2,x=v*-e*q/d+(c+j)/2,y=N.asin(((c-x)/e).toFixed(9)),z=N.asin(((j-x)/e).toFixed(9));y=w>b?O-y:y,z=w>i?O-z:z,0>y&&(y=2*O+y),0>z&&(z=2*O+z),h&&y>z&&(y-=2*O),!h&&z>y&&(z-=2*O)}var A=z-y;if(S(A)>m){var B=z,D=i,E=j;z=y+m*(h&&z>y?1:-1),i=w+d*N.cos(z),j=x+e*N.sin(z),o=C(i,j,d,e,f,0,h,D,E,[z,B,w,x])}A=z-y;var F=N.cos(y),G=N.sin(y),H=N.cos(z),I=N.sin(z),J=N.tan(A/4),K=4/3*d*J,L=4/3*e*J,M=[b,c],P=[b+K*G,c-L*F],Q=[i+K*I,j-L*H],R=[i,j];if(P[0]=2*M[0]-P[0],P[1]=2*M[1]-P[1],k)return[P,Q,R].concat(o);o=[P,Q,R].concat(o).join().split(",");for(var T=[],U=0,V=o.length;V>U;U++)T[U]=U%2?p(o[U-1],o[U],n).y:p(o[U],o[U+1],n).x;return T}function D(a,b,c,d,e,f,g,h){for(var i,j,k,l,m,n,o,p,q=[],r=[[],[]],s=0;2>s;++s)if(0==s?(j=6*a-12*c+6*e,i=-3*a+9*c-9*e+3*g,k=3*c-3*a):(j=6*b-12*d+6*f,i=-3*b+9*d-9*f+3*h,k=3*d-3*b),S(i)<1e-12){if(S(j)<1e-12)continue;l=-k/j,l>0&&1>l&&q.push(l)}else o=j*j-4*k*i,p=N.sqrt(o),0>o||(m=(-j+p)/(2*i),m>0&&1>m&&q.push(m),n=(-j-p)/(2*i),n>0&&1>n&&q.push(n));for(var t,u=q.length,v=u;u--;)l=q[u],t=1-l,r[0][u]=t*t*t*a+3*t*t*l*c+3*t*l*l*e+l*l*l*g,r[1][u]=t*t*t*b+3*t*t*l*d+3*t*l*l*f+l*l*l*h;return r[0][v]=a,r[1][v]=b,r[0][v+1]=g,r[1][v+1]=h,r[0].length=r[1].length=v+2,{min:{x:P.apply(0,r[0]),y:P.apply(0,r[1])},max:{x:Q.apply(0,r[0]),y:Q.apply(0,r[1])}}}function E(a,b){var d=!b&&c(a);if(!b&&d.curve)return f(d.curve);for(var e=z(a),g=b&&z(b),h={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},i={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},j=(function(a,b,c){var d,e;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];switch(!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null),a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"].concat(C.apply(0,[b.x,b.y].concat(a.slice(1))));break;case"S":"C"==c||"S"==c?(d=2*b.x-b.bx,e=2*b.y-b.by):(d=b.x,e=b.y),a=["C",d,e].concat(a.slice(1));break;case"T":"Q"==c||"T"==c?(b.qx=2*b.x-b.qx,b.qy=2*b.y-b.qy):(b.qx=b.x,b.qy=b.y),a=["C"].concat(B(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"].concat(B(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"].concat(A(b.x,b.y,a[1],a[2]));break;case"H":a=["C"].concat(A(b.x,b.y,a[1],b.y));break;case"V":a=["C"].concat(A(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"].concat(A(b.x,b.y,b.X,b.Y))}return a}),k=function(a,b){if(a[b].length>7){a[b].shift();for(var c=a[b];c.length;)m[b]="A",g&&(n[b]="A"),a.splice(b++,0,["C"].concat(c.splice(0,6)));a.splice(b,1),r=Q(e.length,g&&g.length||0)}},l=function(a,b,c,d,f){a&&b&&"M"==a[f][0]&&"M"!=b[f][0]&&(b.splice(f,0,["M",d.x,d.y]),c.bx=0,c.by=0,c.x=a[f][1],c.y=a[f][2],r=Q(e.length,g&&g.length||0))},m=[],n=[],o="",p="",q=0,r=Q(e.length,g&&g.length||0);r>q;q++){e[q]&&(o=e[q][0]),"C"!=o&&(m[q]=o,q&&(p=m[q-1])),e[q]=j(e[q],h,p),"A"!=m[q]&&"C"==o&&(m[q]="C"),k(e,q),g&&(g[q]&&(o=g[q][0]),"C"!=o&&(n[q]=o,q&&(p=n[q-1])),g[q]=j(g[q],i,p),"A"!=n[q]&&"C"==o&&(n[q]="C"),k(g,q)),l(e,g,h,i,q),l(g,e,i,h,q);var s=e[q],t=g&&g[q],u=s.length,v=g&&t.length;h.x=s[u-2],h.y=s[u-1],h.bx=M(s[u-4])||h.x,h.by=M(s[u-3])||h.y,i.bx=g&&(M(t[v-4])||i.x),i.by=g&&(M(t[v-3])||i.y),i.x=g&&t[v-2],i.y=g&&t[v-1]}return g||(d.curve=f(e)),g?[e,g]:e}function F(a,b){if(!b)return a;var c,d,e,f,g,h,i;for(a=E(a),e=0,g=a.length;g>e;e++)for(i=a[e],f=1,h=i.length;h>f;f+=2)c=b.x(i[f],i[f+1]),d=b.y(i[f],i[f+1]),i[f]=c,i[f+1]=d;return a}function G(a,b){for(var c=[],d=0,e=a.length;e-2*!b>d;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}var H=b.prototype,I=a.is,J=a._.clone,K="hasOwnProperty",L=/,?([a-z]),?/gi,M=parseFloat,N=Math,O=N.PI,P=N.min,Q=N.max,R=N.pow,S=N.abs,T=h(1),U=h(),V=h(0,1),W=a._unit2px,X={path:function(a){return a.attr("path")},circle:function(a){var b=W(a);return x(b.cx,b.cy,b.r)},ellipse:function(a){var b=W(a);return x(b.cx||0,b.cy||0,b.rx,b.ry)},rect:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height,b.rx,b.ry)},image:function(a){var b=W(a);return w(b.x||0,b.y||0,b.width,b.height)},line:function(a){return"M"+[a.attr("x1")||0,a.attr("y1")||0,a.attr("x2"),a.attr("y2")]},polyline:function(a){return"M"+a.attr("points")},polygon:function(a){return"M"+a.attr("points")+"z"},deflt:function(a){var b=a.node.getBBox();return w(b.x,b.y,b.width,b.height)}};a.path=c,a.path.getTotalLength=T,a.path.getPointAtLength=U,a.path.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return V(a,b).end;var d=V(a,c,1);return b?V(d,b).end:d},H.getTotalLength=function(){return this.node.getTotalLength?this.node.getTotalLength():void 0},H.getPointAtLength=function(a){return U(this.attr("d"),a)},H.getSubpath=function(b,c){return a.path.getSubpath(this.attr("d"),b,c)},a._.box=d,a.path.findDotsAtSegment=i,a.path.bezierBBox=j,a.path.isPointInsideBBox=k,a.closest=function(b,c,e,f){for(var g=100,h=d(b-g/2,c-g/2,g,g),i=[],j=e[0].hasOwnProperty("x")?function(a){return{x:e[a].x,y:e[a].y}}:function(a){return{x:e[a],y:f[a]}},l=0;1e6>=g&&!l;){for(var m=0,n=e.length;n>m;m++){var o=j(m);if(k(h,o.x,o.y)){l++,i.push(o);break}}l||(g*=2,h=d(b-g/2,c-g/2,g,g))}if(1e6!=g){var p,q=1/0;for(m=0,n=i.length;n>m;m++){var r=a.len(b,c,i[m].x,i[m].y);q>r&&(q=r,i[m].len=r,p=i[m])}return p}},a.path.isBBoxIntersect=l,a.path.intersection=r,a.path.intersectionNumber=s,a.path.isPointInside=u,a.path.getBBox=v,a.path.get=X,a.path.toRelative=y,a.path.toAbsolute=z,a.path.toCubic=E,a.path.map=F,a.path.toString=e,a.path.clone=f}),d.plugin(function(a){var d=Math.max,e=Math.min,f=function(a){if(this.items=[],this.bindings={},this.length=0,this.type="set",a)for(var b=0,c=a.length;c>b;b++)a[b]&&(this[this.items.length]=this.items[this.items.length]=a[b],this.length++)},g=f.prototype;g.push=function(){for(var a,b,c=0,d=arguments.length;d>c;c++)a=arguments[c],a&&(b=this.items.length,this[b]=this.items[b]=a,this.length++);return this},g.pop=function(){return this.length&&delete this[this.length--],this.items.pop()},g.forEach=function(a,b){for(var c=0,d=this.items.length;d>c;c++)if(a.call(b,this.items[c],c)===!1)return this;return this},g.animate=function(d,e,f,g){"function"!=typeof f||f.length||(g=f,f=c.linear),d instanceof a._.Animation&&(g=d.callback,f=d.easing,e=f.dur,d=d.attr);var h=arguments;if(a.is(d,"array")&&a.is(h[h.length-1],"array"))var i=!0;var j,k=function(){j?this.b=j:j=this.b},l=0,m=this,n=g&&function(){++l==m.length&&g.call(this) +};return this.forEach(function(a,c){b.once("snap.animcreated."+a.id,k),i?h[c]&&a.animate.apply(a,h[c]):a.animate(d,e,f,n)})},g.remove=function(){for(;this.length;)this.pop().remove();return this},g.bind=function(a,b,c){var d={};if("function"==typeof b)this.bindings[a]=b;else{var e=c||a;this.bindings[a]=function(a){d[e]=a,b.attr(d)}}return this},g.attr=function(a){var b={};for(var c in a)this.bindings[c]?this.bindings[c](a[c]):b[c]=a[c];for(var d=0,e=this.items.length;e>d;d++)this.items[d].attr(b);return this},g.clear=function(){for(;this.length;)this.pop()},g.splice=function(a,b){a=0>a?d(this.length+a,0):a,b=d(0,e(this.length-a,b));var c,g=[],h=[],i=[];for(c=2;c<arguments.length;c++)i.push(arguments[c]);for(c=0;b>c;c++)h.push(this[a+c]);for(;c<this.length-a;c++)g.push(this[a+c]);var j=i.length;for(c=0;c<j+g.length;c++)this.items[a+c]=this[a+c]=j>c?i[c]:g[c-j];for(c=this.items.length=this.length-=b-j;this[c];)delete this[c++];return new f(h)},g.exclude=function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]==a)return this.splice(b,1),!0;return!1},g.insertAfter=function(a){for(var b=this.items.length;b--;)this.items[b].insertAfter(a);return this},g.getBBox=function(){for(var a=[],b=[],c=[],f=[],g=this.items.length;g--;)if(!this.items[g].removed){var h=this.items[g].getBBox();a.push(h.x),b.push(h.y),c.push(h.x+h.width),f.push(h.y+h.height)}return a=e.apply(0,a),b=e.apply(0,b),c=d.apply(0,c),f=d.apply(0,f),{x:a,y:b,x2:c,y2:f,width:c-a,height:f-b,cx:a+(c-a)/2,cy:b+(f-b)/2}},g.clone=function(a){a=new f;for(var b=0,c=this.items.length;c>b;b++)a.push(this.items[b].clone());return a},g.toString=function(){return"Snap‘s set"},g.type="set",a.Set=f,a.set=function(){var a=new f;return arguments.length&&a.push.apply(a,Array.prototype.slice.call(arguments,0)),a}}),d.plugin(function(a,c){function d(a){var b=a[0];switch(b.toLowerCase()){case"t":return[b,0,0];case"m":return[b,1,0,0,1,0,0];case"r":return 4==a.length?[b,0,a[2],a[3]]:[b,0];case"s":return 5==a.length?[b,1,1,a[3],a[4]]:3==a.length?[b,1,1]:[b,1]}}function e(b,c,e){c=p(c).replace(/\.{3}|\u2026/g,b),b=a.parseTransformString(b)||[],c=a.parseTransformString(c)||[];for(var f,g,h,i,l=Math.max(b.length,c.length),m=[],n=[],o=0;l>o;o++){if(h=b[o]||d(c[o]),i=c[o]||d(h),h[0]!=i[0]||"r"==h[0].toLowerCase()&&(h[2]!=i[2]||h[3]!=i[3])||"s"==h[0].toLowerCase()&&(h[3]!=i[3]||h[4]!=i[4])){b=a._.transform2matrix(b,e()),c=a._.transform2matrix(c,e()),m=[["m",b.a,b.b,b.c,b.d,b.e,b.f]],n=[["m",c.a,c.b,c.c,c.d,c.e,c.f]];break}for(m[o]=[],n[o]=[],f=0,g=Math.max(h.length,i.length);g>f;f++)f in h&&(m[o][f]=h[f]),f in i&&(n[o][f]=i[f])}return{from:k(m),to:k(n),f:j(m)}}function f(a){return a}function g(a){return function(b){return+b.toFixed(3)+a}}function h(a){return a.join(" ")}function i(b){return a.rgb(b[0],b[1],b[2])}function j(a){var b,c,d,e,f,g,h=0,i=[];for(b=0,c=a.length;c>b;b++){for(f="[",g=['"'+a[b][0]+'"'],d=1,e=a[b].length;e>d;d++)g[d]="val["+h++ +"]";f+=g+"]",i[b]=f}return Function("val","return Snap.path.toString.call(["+i+"])")}function k(a){for(var b=[],c=0,d=a.length;d>c;c++)for(var e=1,f=a[c].length;f>e;e++)b.push(a[c][e]);return b}function l(a){return isFinite(parseFloat(a))}function m(b,c){return a.is(b,"array")&&a.is(c,"array")?b.toString()==c.toString():!1}var n={},o=/[a-z]+$/i,p=String;n.stroke=n.fill="colour",c.prototype.equal=function(a,c){return b("snap.util.equal",this,a,c).firstDefined()},b.on("snap.util.equal",function(b,c){var d,q,r=p(this.attr(b)||""),s=this;if(l(r)&&l(c))return{from:parseFloat(r),to:parseFloat(c),f:f};if("colour"==n[b])return d=a.color(r),q=a.color(c),{from:[d.r,d.g,d.b,d.opacity],to:[q.r,q.g,q.b,q.opacity],f:i};if("viewBox"==b)return d=this.attr(b).vb.split(" ").map(Number),q=c.split(" ").map(Number),{from:d,to:q,f:h};if("transform"==b||"gradientTransform"==b||"patternTransform"==b)return c instanceof a.Matrix&&(c=c.toTransformString()),a._.rgTransform.test(c)||(c=a._.svgTransform2string(c)),e(r,c,function(){return s.getBBox(1)});if("d"==b||"path"==b)return d=a.path.toCubic(r,c),{from:k(d[0]),to:k(d[1]),f:j(d[0])};if("points"==b)return d=p(r).split(a._.separator),q=p(c).split(a._.separator),{from:d,to:q,f:function(a){return a}};var t=r.match(o),u=p(c).match(o);return t&&m(t,u)?{from:parseFloat(r),to:parseFloat(c),f:g(t)}:{from:this.asPX(b),to:this.asPX(b,c),f:f}})}),d.plugin(function(a,c,d,e){for(var f=c.prototype,g="hasOwnProperty",h=("createTouch"in e.doc),i=["click","dblclick","mousedown","mousemove","mouseout","mouseover","mouseup","touchstart","touchmove","touchend","touchcancel"],j={mousedown:"touchstart",mousemove:"touchmove",mouseup:"touchend"},k=(function(a,b){var c="y"==a?"scrollTop":"scrollLeft",d=b&&b.node?b.node.ownerDocument:e.doc;return d[c in d.documentElement?"documentElement":"body"][c]}),l=function(){return this.originalEvent.preventDefault()},m=function(){return this.originalEvent.stopPropagation()},n=function(a,b,c,d){var e=h&&j[b]?j[b]:b,f=function(e){var f=k("y",d),i=k("x",d);if(h&&j[g](b))for(var n=0,o=e.targetTouches&&e.targetTouches.length;o>n;n++)if(e.targetTouches[n].target==a||a.contains(e.targetTouches[n].target)){var p=e;e=e.targetTouches[n],e.originalEvent=p,e.preventDefault=l,e.stopPropagation=m;break}var q=e.clientX+i,r=e.clientY+f;return c.call(d,e,q,r)};return b!==e&&a.addEventListener(b,f,!1),a.addEventListener(e,f,!1),function(){return b!==e&&a.removeEventListener(b,f,!1),a.removeEventListener(e,f,!1),!0}},o=[],p=function(a){for(var c,d=a.clientX,e=a.clientY,f=k("y"),g=k("x"),i=o.length;i--;){if(c=o[i],h){for(var j,l=a.touches&&a.touches.length;l--;)if(j=a.touches[l],j.identifier==c.el._drag.id||c.el.node.contains(j.target)){d=j.clientX,e=j.clientY,(a.originalEvent?a.originalEvent:a).preventDefault();break}}else a.preventDefault();{var m=c.el.node;m.nextSibling,m.parentNode,m.style.display}d+=g,e+=f,b("snap.drag.move."+c.el.id,c.move_scope||c.el,d-c.el._drag.x,e-c.el._drag.y,d,e,a)}},q=function(c){a.unmousemove(p).unmouseup(q);for(var d,e=o.length;e--;)d=o[e],d.el._drag={},b("snap.drag.end."+d.el.id,d.end_scope||d.start_scope||d.move_scope||d.el,c),b.off("snap.drag.*."+d.el.id);o=[]},r=i.length;r--;)!function(b){a[b]=f[b]=function(c,d){if(a.is(c,"function"))this.events=this.events||[],this.events.push({name:b,f:c,unbind:n(this.node||document,b,c,d||this)});else for(var e=0,f=this.events.length;f>e;e++)if(this.events[e].name==b)try{this.events[e].f.call(this)}catch(g){}return this},a["un"+b]=f["un"+b]=function(a){for(var c=this.events||[],d=c.length;d--;)if(c[d].name==b&&(c[d].f==a||!a))return c[d].unbind(),c.splice(d,1),!c.length&&delete this.events,this;return this}}(i[r]);f.hover=function(a,b,c,d){return this.mouseover(a,c).mouseout(b,d||c)},f.unhover=function(a,b){return this.unmouseover(a).unmouseout(b)};var s=[];f.drag=function(c,d,e,f,g,h){function i(i,j,l){(i.originalEvent||i).preventDefault(),k._drag.x=j,k._drag.y=l,k._drag.id=i.identifier,!o.length&&a.mousemove(p).mouseup(q),o.push({el:k,move_scope:f,start_scope:g,end_scope:h}),d&&b.on("snap.drag.start."+k.id,d),c&&b.on("snap.drag.move."+k.id,c),e&&b.on("snap.drag.end."+k.id,e),b("snap.drag.start."+k.id,g||f||k,j,l,i)}function j(a,c,d){b("snap.draginit."+k.id,k,a,c,d)}var k=this;if(!arguments.length){var l;return k.drag(function(a,b){this.attr({transform:l+(l?"T":"t")+[a,b]})},function(){l=this.transform().local})}return b.on("snap.draginit."+k.id,i),k._drag={},s.push({el:k,start:i,init:j}),k.mousedown(j),k},f.undrag=function(){for(var c=s.length;c--;)s[c].el==this&&(this.unmousedown(s[c].init),s.splice(c,1),b.unbind("snap.drag.*."+this.id),b.unbind("snap.draginit."+this.id));return!s.length&&a.unmousemove(p).unmouseup(q),this}}),d.plugin(function(a,c,d){var e=(c.prototype,d.prototype),f=/^\s*url\((.+)\)/,g=String,h=a._.$;a.filter={},e.filter=function(b){var d=this;"svg"!=d.type&&(d=d.paper);var e=a.parse(g(b)),f=a._.id(),i=(d.node.offsetWidth,d.node.offsetHeight,h("filter"));return h(i,{id:f,filterUnits:"userSpaceOnUse"}),i.appendChild(e.node),d.defs.appendChild(i),new c(i)},b.on("snap.util.getattr.filter",function(){b.stop();var c=h(this.node,"filter");if(c){var d=g(c).match(f);return d&&a.select(d[1])}}),b.on("snap.util.attr.filter",function(d){if(d instanceof c&&"filter"==d.type){b.stop();var e=d.node.id;e||(h(d.node,{id:d.id}),e=d.id),h(this.node,{filter:a.url(e)})}d&&"none"!=d||(b.stop(),this.node.removeAttribute("filter"))}),a.filter.blur=function(b,c){null==b&&(b=2);var d=null==c?b:[b,c];return a.format('<feGaussianBlur stdDeviation="{def}"/>',{def:d})},a.filter.blur.toString=function(){return this()},a.filter.shadow=function(b,c,d,e,f){return"string"==typeof d&&(e=d,f=e,d=4),"string"!=typeof e&&(f=e,e="#000"),e=e||"#000",null==d&&(d=4),null==f&&(f=1),null==b&&(b=0,c=2),null==c&&(c=b),e=a.color(e),a.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>',{color:e,dx:b,dy:c,blur:d,opacity:f})},a.filter.shadow.toString=function(){return this()},a.filter.grayscale=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>',{a:.2126+.7874*(1-b),b:.7152-.7152*(1-b),c:.0722-.0722*(1-b),d:.2126-.2126*(1-b),e:.7152+.2848*(1-b),f:.0722-.0722*(1-b),g:.2126-.2126*(1-b),h:.0722+.9278*(1-b)})},a.filter.grayscale.toString=function(){return this()},a.filter.sepia=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>',{a:.393+.607*(1-b),b:.769-.769*(1-b),c:.189-.189*(1-b),d:.349-.349*(1-b),e:.686+.314*(1-b),f:.168-.168*(1-b),g:.272-.272*(1-b),h:.534-.534*(1-b),i:.131+.869*(1-b)})},a.filter.sepia.toString=function(){return this()},a.filter.saturate=function(b){return null==b&&(b=1),a.format('<feColorMatrix type="saturate" values="{amount}"/>',{amount:1-b})},a.filter.saturate.toString=function(){return this()},a.filter.hueRotate=function(b){return b=b||0,a.format('<feColorMatrix type="hueRotate" values="{angle}"/>',{angle:b})},a.filter.hueRotate.toString=function(){return this()},a.filter.invert=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>',{amount:b,amount2:1-b})},a.filter.invert.toString=function(){return this()},a.filter.brightness=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>',{amount:b})},a.filter.brightness.toString=function(){return this()},a.filter.contrast=function(b){return null==b&&(b=1),a.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>',{amount:b,amount2:.5-b/2})},a.filter.contrast.toString=function(){return this()}}),d.plugin(function(a,b){var c=a._.box,d=a.is,e=/^[^a-z]*([tbmlrc])/i,f=function(){return"T"+this.dx+","+this.dy};b.prototype.getAlign=function(a,b){null==b&&d(a,"string")&&(b=a,a=null),a=a||this.paper;var g=a.getBBox?a.getBBox():c(a),h=this.getBBox(),i={};switch(b=b&&b.match(e),b=b?b[1].toLowerCase():"c"){case"t":i.dx=0,i.dy=g.y-h.y;break;case"b":i.dx=0,i.dy=g.y2-h.y2;break;case"m":i.dx=0,i.dy=g.cy-h.cy;break;case"l":i.dx=g.x-h.x,i.dy=0;break;case"r":i.dx=g.x2-h.x2,i.dy=0;break;default:i.dx=g.cx-h.cx,i.dy=0}return i.toString=f,i},b.prototype.align=function(a,b){return this.transform("..."+this.getAlign(a,b))}}),d}); diff --git a/web/pgadmin/misc/static/explain/js/snap.svg.js b/web/pgadmin/misc/static/explain/js/snap.svg.js new file mode 100644 index 0000000..ef0fb6d --- /dev/null +++ b/web/pgadmin/misc/static/explain/js/snap.svg.js @@ -0,0 +1,8149 @@ +// Snap.svg 0.4.1 +// Copyright (c) 2013 – 2015 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// build: 2015-04-13 +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ┌────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.4.2 - JavaScript Events Library │ \\ +// ├────────────────────────────────────────────────────────────┤ \\ +// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// └────────────────────────────────────────────────────────────┘ \\ +(function (glob) { + var version = "0.4.2", + has = "hasOwnProperty", + separator = /[\.\/]/, + comaseparator = /\s*,\s*/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + firstDefined = function () { + for (var i = 0, ii = this.length; i < ii; i++) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + lastDefined = function () { + var i = this.length; + while (--i) { + if (typeof this[i] != "undefined") { + return this[i]; + } + } + }, + /*\ + * eve + [ method ] + * Fires event with given `name`, given scope and other parameters. + > Arguments + - name (string) name of the *event*, dot (`.`) or slash (`/`) separated + - scope (object) context for the event handlers + - varargs (...) the rest of arguments will be sent to event handlers + = (object) array of returned values from the listeners. Array has two methods `.firstDefined()` and `.lastDefined()` to get first or last not `undefined` value. + \*/ + eve = function (name, scope) { + name = String(name); + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + ce = current_event, + errors = []; + out.firstDefined = firstDefined; + out.lastDefined = lastDefined; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + break; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + break; + } + } + } + stop = oldstop; + current_event = ce; + return out; + }; + // Undocumented. Debug only. + eve._events = events; + /*\ + * eve.listeners + [ method ] + * Internal method which gives you array of all event handlers that will be triggered by the given `name`. + > Arguments + - name (string) name of the event, dot (`.`) or slash (`/`) separated + = (array) array of event handlers + \*/ + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + /*\ + * eve.on + [ method ] + ** + * Binds given event handler with a given name. You can use wildcards “`*`” for the names: + | eve.on("*.under.*", f); + | eve("mouse.under.floor"); // triggers f + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. + > Example: + | eve.on("mouse", eatIt)(2); + | eve.on("mouse", scream); + | eve.on("mouse", catchIt)(1); + * This will ensure that `catchIt` function will be called before `eatIt`. + * + * If you want to put your handler before non-indexed handlers, specify a negative value. + * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. + \*/ + eve.on = function (name, f) { + name = String(name); + if (typeof f != "function") { + return function () {}; + } + var names = name.split(comaseparator); + for (var i = 0, ii = names.length; i < ii; i++) { + (function (name) { + var names = name.split(separator), + e = events, + exist; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + exist = true; + break; + } + !exist && e.f.push(f); + }(names[i])); + } + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + /*\ + * eve.f + [ method ] + ** + * Returns function that will fire given event with optional arguments. + * Arguments that will be passed to the result function will be also + * concated to the list of final arguments. + | el.onclick = eve.f("click", 1, 2); + | eve.on("click", function (a, b, c) { + | console.log(a, b, c); // 1, 2, [event object] + | }); + > Arguments + - event (string) event name + - varargs (…) and any other arguments + = (function) possible event handler function + \*/ + eve.f = function (event) { + var attrs = [].slice.call(arguments, 1); + return function () { + eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); + }; + }; + /*\ + * eve.stop + [ method ] + ** + * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. + \*/ + eve.stop = function () { + stop = 1; + }; + /*\ + * eve.nt + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + > Arguments + ** + - subname (string) #optional subname of the event + ** + = (string) name of the event, if `subname` is not specified + * or + = (boolean) `true`, if current event’s name contains `subname` + \*/ + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + /*\ + * eve.nts + [ method ] + ** + * Could be used inside event handler to figure out actual name of the event. + ** + ** + = (array) names of the event + \*/ + eve.nts = function () { + return current_event.split(separator); + }; + /*\ + * eve.off + [ method ] + ** + * Removes given function from the list of event listeners assigned to given name. + * If no arguments specified all the events will be cleared. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + \*/ + /*\ + * eve.unbind + [ method ] + ** + * See @eve.off + \*/ + eve.off = eve.unbind = function (name, f) { + if (!name) { + eve._events = events = {n: {}}; + return; + } + var names = name.split(comaseparator); + if (names.length > 1) { + for (var i = 0, ii = names.length; i < ii; i++) { + eve.off(names[i], f); + } + return; + } + names = name.split(separator); + var e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + /*\ + * eve.once + [ method ] + ** + * Binds given event handler with a given name to only run once then unbind itself. + | eve.once("login", f); + | eve("login"); // triggers f + | eve("login"); // no listeners + * Use @eve to trigger the listener. + ** + > Arguments + ** + - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards + - f (function) event handler function + ** + = (function) same return function as @eve.on + \*/ + eve.once = function (name, f) { + var f2 = function () { + eve.unbind(name, f2); + return f.apply(this, arguments); + }; + return eve.on(name, f2); + }; + /*\ + * eve.version + [ property (string) ] + ** + * Current version of the library. + \*/ + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define === "function" && define.amd ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); +})(this); + +(function (glob, factory) { + // AMD support + if (typeof define == "function" && define.amd) { + // Define as an anonymous module + define(["eve"], function (eve) { + return factory(glob, eve); + }); + } else if (typeof exports != 'undefined') { + // Next for Node.js or CommonJS + var eve = require('eve'); + module.exports = factory(glob, eve); + } else { + // Browser globals (glob is window) + // Snap adds itself to window + factory(glob, glob.eve); + } +}(window || this, function (window, eve) { +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +var mina = (function (eve) { + var animations = {}, + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + isArray = Array.isArray || function (a) { + return a instanceof Array || + Object.prototype.toString.call(a) == "[object Array]"; + }, + idgen = 0, + idprefix = "M" + (+new Date).toString(36), + ID = function () { + return idprefix + (idgen++).toString(36); + }, + diff = function (a, b, A, B) { + if (isArray(a)) { + res = []; + for (var i = 0, ii = a.length; i < ii; i++) { + res[i] = diff(a[i], b, A[i], B); + } + return res; + } + var dif = (A - a) / (B - b); + return function (bb) { + return a + dif * (bb - b); + }; + }, + timer = Date.now || function () { + return +new Date; + }, + sta = function (val) { + var a = this; + if (val == null) { + return a.s; + } + var ds = a.s - val; + a.b += a.dur * ds; + a.B += a.dur * ds; + a.s = val; + }, + speed = function (val) { + var a = this; + if (val == null) { + return a.spd; + } + a.spd = val; + }, + duration = function (val) { + var a = this; + if (val == null) { + return a.dur; + } + a.s = a.s * val / a.dur; + a.dur = val; + }, + stopit = function () { + var a = this; + delete animations[a.id]; + a.update(); + eve("mina.stop." + a.id, a); + }, + pause = function () { + var a = this; + if (a.pdif) { + return; + } + delete animations[a.id]; + a.update(); + a.pdif = a.get() - a.b; + }, + resume = function () { + var a = this; + if (!a.pdif) { + return; + } + a.b = a.get() - a.pdif; + delete a.pdif; + animations[a.id] = a; + }, + update = function () { + var a = this, + res; + if (isArray(a.start)) { + res = []; + for (var j = 0, jj = a.start.length; j < jj; j++) { + res[j] = +a.start[j] + + (a.end[j] - a.start[j]) * a.easing(a.s); + } + } else { + res = +a.start + (a.end - a.start) * a.easing(a.s); + } + a.set(res); + }, + frame = function () { + var len = 0; + for (var i in animations) if (animations.hasOwnProperty(i)) { + var a = animations[i], + b = a.get(), + res; + len++; + a.s = (b - a.b) / (a.dur / a.spd); + if (a.s >= 1) { + delete animations[i]; + a.s = 1; + len--; + (function (a) { + setTimeout(function () { + eve("mina.finish." + a.id, a); + }); + }(a)); + } + a.update(); + } + len && requestAnimFrame(frame); + }, + /*\ + * mina + [ method ] + ** + * Generic animation of numbers + ** + - a (number) start _slave_ number + - A (number) end _slave_ number + - b (number) start _master_ number (start time in general case) + - B (number) end _master_ number (end time in gereal case) + - get (function) getter of _master_ number (see @mina.time) + - set (function) setter of _slave_ number + - easing (function) #optional easing function, default is @mina.linear + = (object) animation descriptor + o { + o id (string) animation id, + o start (number) start _slave_ number, + o end (number) end _slave_ number, + o b (number) start _master_ number, + o s (number) animation status (0..1), + o dur (number) animation duration, + o spd (number) animation speed, + o get (function) getter of _master_ number (see @mina.time), + o set (function) setter of _slave_ number, + o easing (function) easing function, default is @mina.linear, + o status (function) status getter/setter, + o speed (function) speed getter/setter, + o duration (function) duration getter/setter, + o stop (function) animation stopper + o pause (function) pauses the animation + o resume (function) resumes the animation + o update (function) calles setter with the right value of the animation + o } + \*/ + mina = function (a, A, b, B, get, set, easing) { + var anim = { + id: ID(), + start: a, + end: A, + b: b, + s: 0, + dur: B - b, + spd: 1, + get: get, + set: set, + easing: easing || mina.linear, + status: sta, + speed: speed, + duration: duration, + stop: stopit, + pause: pause, + resume: resume, + update: update + }; + animations[anim.id] = anim; + var len = 0, i; + for (i in animations) if (animations.hasOwnProperty(i)) { + len++; + if (len == 2) { + break; + } + } + len == 1 && requestAnimFrame(frame); + return anim; + }; + /*\ + * mina.time + [ method ] + ** + * Returns the current time. Equivalent to: + | function () { + | return (new Date).getTime(); + | } + \*/ + mina.time = timer; + /*\ + * mina.getById + [ method ] + ** + * Returns an animation by its id + - id (string) animation's id + = (object) See @mina + \*/ + mina.getById = function (id) { + return animations[id] || null; + }; + + /*\ + * mina.linear + [ method ] + ** + * Default linear easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.linear = function (n) { + return n; + }; + /*\ + * mina.easeout + [ method ] + ** + * Easeout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeout = function (n) { + return Math.pow(n, 1.7); + }; + /*\ + * mina.easein + [ method ] + ** + * Easein easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easein = function (n) { + return Math.pow(n, .48); + }; + /*\ + * mina.easeinout + [ method ] + ** + * Easeinout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.easeinout = function (n) { + if (n == 1) { + return 1; + } + if (n == 0) { + return 0; + } + var q = .48 - n / 1.04, + Q = Math.sqrt(.1734 + q * q), + x = Q - q, + X = Math.pow(Math.abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = Math.pow(Math.abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }; + /*\ + * mina.backin + [ method ] + ** + * Backin easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backin = function (n) { + if (n == 1) { + return 1; + } + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }; + /*\ + * mina.backout + [ method ] + ** + * Backout easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.backout = function (n) { + if (n == 0) { + return 0; + } + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }; + /*\ + * mina.elastic + [ method ] + ** + * Elastic easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.elastic = function (n) { + if (n == !!n) { + return n; + } + return Math.pow(2, -10 * n) * Math.sin((n - .075) * + (2 * Math.PI) / .3) + 1; + }; + /*\ + * mina.bounce + [ method ] + ** + * Bounce easing + - n (number) input 0..1 + = (number) output 0..1 + \*/ + mina.bounce = function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + }; + window.mina = mina; + return mina; +})(typeof eve == "undefined" ? function () {} : eve); +// Copyright (c) 2013 - 2015 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var Snap = (function(root) { +Snap.version = "0.4.0"; +/*\ + * Snap + [ method ] + ** + * Creates a drawing surface or wraps existing SVG element. + ** + - width (number|string) width of surface + - height (number|string) height of surface + * or + - DOM (SVGElement) element to be wrapped into Snap structure + * or + - array (array) array of elements (will return set of elements) + * or + - query (string) CSS query selector + = (object) @Element +\*/ +function Snap(w, h) { + if (w) { + if (w.nodeType) { + return wrap(w); + } + if (is(w, "array") && Snap.set) { + return Snap.set.apply(Snap, w); + } + if (w instanceof Element) { + return w; + } + if (h == null) { + w = glob.doc.querySelector(String(w)); + return wrap(w); + } + } + w = w == null ? "100%" : w; + h = h == null ? "100%" : h; + return new Paper(w, h); +} +Snap.toString = function () { + return "Snap v" + this.version; +}; +Snap._ = {}; +var glob = { + win: root.window, + doc: root.window.document +}; +Snap._.glob = glob; +var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + round = math.round, + E = "", + S = " ", + objectToString = Object.prototype.toString, + ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?%?)\s*\))\s*$/i, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + reURLValue = /^url\(#?([^)]+)\)$/, + separator = Snap._.separator = /[,\s]+/, + whitespace = /[\s]/g, + commaSpaces = /[\s]*,[\s]*/, + hsrg = {hs: 1, rg: 1}, + pathCommand = /([a-z])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\s]*,?[\s]*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\\d+)?)[\s]*,?[\s]*/ig, + idgen = 0, + idprefix = "S" + (+new Date).toString(36), + ID = function (el) { + return (el && el.type ? el.type : E) + idprefix + (idgen++).toString(36); + }, + xlink = "http://www.w3.org/1999/xlink", + xmlns = "http://www.w3.org/2000/svg", + hub = {}, + URL = Snap.url = function (url) { + return "url('#" + url + "')"; + }; + +function $(el, attr) { + if (attr) { + if (el == "#text") { + el = glob.doc.createTextNode(attr.text || attr["#text"] || ""); + } + if (el == "#comment") { + el = glob.doc.createComment(attr.text || attr["#text"] || ""); + } + if (typeof el == "string") { + el = $(el); + } + if (typeof attr == "string") { + if (el.nodeType == 1) { + if (attr.substring(0, 6) == "xlink:") { + return el.getAttributeNS(xlink, attr.substring(6)); + } + if (attr.substring(0, 4) == "xml:") { + return el.getAttributeNS(xmlns, attr.substring(4)); + } + return el.getAttribute(attr); + } else if (attr == "text") { + return el.nodeValue; + } else { + return null; + } + } + if (el.nodeType == 1) { + for (var key in attr) if (attr[has](key)) { + var val = Str(attr[key]); + if (val) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), val); + } else if (key.substring(0, 4) == "xml:") { + el.setAttributeNS(xmlns, key.substring(4), val); + } else { + el.setAttribute(key, val); + } + } else { + el.removeAttribute(key); + } + } + } else if ("text" in attr) { + el.nodeValue = attr.text; + } + } else { + el = glob.doc.createElementNS(xmlns, el); + } + return el; +} +Snap._.$ = $; +Snap._.id = ID; +function getAttrs(el) { + var attrs = el.attributes, + name, + out = {}; + for (var i = 0; i < attrs.length; i++) { + if (attrs[i].namespaceURI == xlink) { + name = "xlink:"; + } else { + name = ""; + } + name += attrs[i].name; + out[name] = attrs[i].textContent; + } + return out; +} +function is(o, type) { + type = Str.prototype.toLowerCase.call(type); + if (type == "finite") { + return isFinite(o); + } + if (type == "array" && + (o instanceof Array || Array.isArray && Array.isArray(o))) { + return true; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; +} +/*\ + * Snap.format + [ method ] + ** + * Replaces construction of type `{<name>}` to the corresponding argument + ** + - token (string) string to format + - json (object) object which properties are used as a replacement + = (string) formatted string + > Usage + | // this draws a rectangular shape equivalent to "M10,20h40v50h-40z" + | paper.path(Snap.format("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { + | x: 10, + | y: 20, + | dim: { + | width: 40, + | height: 50, + | "negative width": -40 + | } + | })); +\*/ +Snap.format = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return Str(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; +})(); +function clone(obj) { + if (typeof obj == "function" || Object(obj) !== obj) { + return obj; + } + var res = new obj.constructor; + for (var key in obj) if (obj[has](key)) { + res[key] = clone(obj[key]); + } + return res; +} +Snap._.clone = clone; +function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } +} +function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f.apply(scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; +} +Snap._.cacher = cacher; +function angle(x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return angle(x1, y1, x3, y3) - angle(x2, y2, x3, y3); + } +} +function rad(deg) { + return deg % 360 * PI / 180; +} +function deg(rad) { + return rad * 180 / PI % 360; +} +function x_y() { + return this.x + S + this.y; +} +function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; +} + +/*\ + * Snap.rad + [ method ] + ** + * Transform angle to radians + - deg (number) angle in degrees + = (number) angle in radians +\*/ +Snap.rad = rad; +/*\ + * Snap.deg + [ method ] + ** + * Transform angle to degrees + - rad (number) angle in radians + = (number) angle in degrees +\*/ +Snap.deg = deg; +/*\ + * Snap.sin + [ method ] + ** + * Equivalent to `Math.sin()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) sin +\*/ +Snap.sin = function (angle) { + return math.sin(Snap.rad(angle)); +}; +/*\ + * Snap.tan + [ method ] + ** + * Equivalent to `Math.tan()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) tan +\*/ +Snap.tan = function (angle) { + return math.tan(Snap.rad(angle)); +}; +/*\ + * Snap.cos + [ method ] + ** + * Equivalent to `Math.cos()` only works with degrees, not radians. + - angle (number) angle in degrees + = (number) cos +\*/ +Snap.cos = function (angle) { + return math.cos(Snap.rad(angle)); +}; +/*\ + * Snap.asin + [ method ] + ** + * Equivalent to `Math.asin()` only works with degrees, not radians. + - num (number) value + = (number) asin in degrees +\*/ +Snap.asin = function (num) { + return Snap.deg(math.asin(num)); +}; +/*\ + * Snap.acos + [ method ] + ** + * Equivalent to `Math.acos()` only works with degrees, not radians. + - num (number) value + = (number) acos in degrees +\*/ +Snap.acos = function (num) { + return Snap.deg(math.acos(num)); +}; +/*\ + * Snap.atan + [ method ] + ** + * Equivalent to `Math.atan()` only works with degrees, not radians. + - num (number) value + = (number) atan in degrees +\*/ +Snap.atan = function (num) { + return Snap.deg(math.atan(num)); +}; +/*\ + * Snap.atan2 + [ method ] + ** + * Equivalent to `Math.atan2()` only works with degrees, not radians. + - num (number) value + = (number) atan2 in degrees +\*/ +Snap.atan2 = function (num) { + return Snap.deg(math.atan2(num)); +}; +/*\ + * Snap.angle + [ method ] + ** + * Returns an angle between two or three points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + - x3 (number) #optional x coord of third point + - y3 (number) #optional y coord of third point + = (number) angle in degrees +\*/ +Snap.angle = angle; +/*\ + * Snap.len + [ method ] + ** + * Returns distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len = function (x1, y1, x2, y2) { + return Math.sqrt(Snap.len2(x1, y1, x2, y2)); +}; +/*\ + * Snap.len2 + [ method ] + ** + * Returns squared distance between two points + > Parameters + - x1 (number) x coord of first point + - y1 (number) y coord of first point + - x2 (number) x coord of second point + - y2 (number) y coord of second point + = (number) distance +\*/ +Snap.len2 = function (x1, y1, x2, y2) { + return (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); +}; +/*\ + * Snap.closestPoint + [ method ] + ** + * Returns closest point to a given one on a given path. + > Parameters + - path (Element) path element + - x (number) x coord of a point + - y (number) y coord of a point + = (object) in format + { + x (number) x coord of the point on the path + y (number) y coord of the point on the path + length (number) length of the path to the point + distance (number) distance from the given point to the path + } +\*/ +// Copied from http://bl.ocks.org/mbostock/8027637 +Snap.closestPoint = function (path, x, y) { + function distance2(p) { + var dx = p.x - x, + dy = p.y - y; + return dx * dx + dy * dy; + } + var pathNode = path.node, + pathLength = pathNode.getTotalLength(), + precision = pathLength / pathNode.pathSegList.numberOfItems * .125, + best, + bestLength, + bestDistance = Infinity; + + // linear scan for coarse approximation + for (var scan, scanLength = 0, scanDistance; scanLength <= pathLength; scanLength += precision) { + if ((scanDistance = distance2(scan = pathNode.getPointAtLength(scanLength))) < bestDistance) { + best = scan, bestLength = scanLength, bestDistance = scanDistance; + } + } + + // binary search for precise estimate + precision *= .5; + while (precision > .5) { + var before, + after, + beforeLength, + afterLength, + beforeDistance, + afterDistance; + if ((beforeLength = bestLength - precision) >= 0 && (beforeDistance = distance2(before = pathNode.getPointAtLength(beforeLength))) < bestDistance) { + best = before, bestLength = beforeLength, bestDistance = beforeDistance; + } else if ((afterLength = bestLength + precision) <= pathLength && (afterDistance = distance2(after = pathNode.getPointAtLength(afterLength))) < bestDistance) { + best = after, bestLength = afterLength, bestDistance = afterDistance; + } else { + precision *= .5; + } + } + + best = { + x: best.x, + y: best.y, + length: bestLength, + distance: Math.sqrt(bestDistance) + }; + return best; +} +/*\ + * Snap.is + [ method ] + ** + * Handy replacement for the `typeof` operator + - o (…) any object or primitive + - type (string) name of the type, e.g., `string`, `function`, `number`, etc. + = (boolean) `true` if given value is of given type +\*/ +Snap.is = is; +/*\ + * Snap.snapTo + [ method ] + ** + * Snaps given value to given grid + - values (array|number) given array of values or step of the grid + - value (number) value to adjust + - tolerance (number) #optional maximum distance to the target value that would trigger the snap. Default is `10`. + = (number) adjusted value +\*/ +Snap.snapTo = function (values, value, tolerance) { + tolerance = is(tolerance, "finite") ? tolerance : 10; + if (is(values, "array")) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; +}; +// Colour +/*\ + * Snap.getRGB + [ method ] + ** + * Parses color string as RGB object + - color (string) color string in one of the following formats: + # <ul> + # <li>Color name (<code>red</code>, <code>green</code>, <code>cornflowerblue</code>, etc)</li> + # <li>#••• — shortened HTML color: (<code>#000</code>, <code>#fc0</code>, etc.)</li> + # <li>#•••••• — full length HTML color: (<code>#000000</code>, <code>#bd2300</code>)</li> + # <li>rgb(•••, •••, •••) — red, green and blue channels values: (<code>rgb(200, 100, 0)</code>)</li> + # <li>rgba(•••, •••, •••, •••) — also with opacity</li> + # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (<code>rgb(100%, 175%, 0%)</code>)</li> + # <li>rgba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (<code>hsb(0.5, 0.25, 1)</code>)</li> + # <li>hsba(•••, •••, •••, •••) — also with opacity</li> + # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsba(•••%, •••%, •••%, •••%) — also with opacity</li> + # <li>hsl(•••, •••, •••) — hue, saturation and luminosity values: (<code>hsb(0.5, 0.25, 0.5)</code>)</li> + # <li>hsla(•••, •••, •••, •••) — also with opacity</li> + # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> + # <li>hsla(•••%, •••%, •••%, •••%) — also with opacity</li> + # </ul> + * Note that `%` can be used any time: `rgb(20%, 255, 50%)`. + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) true if string can't be parsed + o } +\*/ +Snap.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: rgbtoString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + if (!colour) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; + } + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6].split(commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red /= 100); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green /= 100); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue /= 100); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return Snap.hsl2rgb(red, green, blue, opacity); + } + red = mmin(math.round(red), 255); + green = mmin(math.round(green), 255); + blue = mmin(math.round(blue), 255); + opacity = mmin(mmax(opacity, 0), 1); + rgb = {r: red, g: green, b: blue, toString: rgbtoString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + rgb.opacity = is(opacity, "finite") ? opacity : 1; + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: rgbtoString}; +}, Snap); +/*\ + * Snap.hsb + [ method ] + ** + * Converts HSB values to a hex representation of the color + - h (number) hue + - s (number) saturation + - b (number) value or brightness + = (string) hex representation of the color +\*/ +Snap.hsb = cacher(function (h, s, b) { + return Snap.hsb2rgb(h, s, b).hex; +}); +/*\ + * Snap.hsl + [ method ] + ** + * Converts HSL values to a hex representation of the color + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (string) hex representation of the color +\*/ +Snap.hsl = cacher(function (h, s, l) { + return Snap.hsl2rgb(h, s, l).hex; +}); +/*\ + * Snap.rgb + [ method ] + ** + * Converts RGB values to a hex representation of the color + - r (number) red + - g (number) green + - b (number) blue + = (string) hex representation of the color +\*/ +Snap.rgb = cacher(function (r, g, b, o) { + if (is(o, "finite")) { + var round = math.round; + return "rgba(" + [round(r), round(g), round(b), +o.toFixed(2)] + ")"; + } + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); +}); +var toHex = function (color) { + var i = glob.doc.getElementsByTagName("head")[0] || glob.doc.getElementsByTagName("svg")[0], + red = "rgb(255, 0, 0)"; + toHex = cacher(function (color) { + if (color.toLowerCase() == "red") { + return red; + } + i.style.color = red; + i.style.color = color; + var out = glob.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + return out == red ? null : out; + }); + return toHex(color); +}, +hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; +}, +hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; +}, +rgbtoString = function () { + return this.opacity == 1 || this.opacity == null ? + this.hex : + "rgba(" + [this.r, this.g, this.b, this.opacity] + ")"; +}, +prepareRGB = function (r, g, b) { + if (g == null && is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && is(r, string)) { + var clr = Snap.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; +}, +packageRGB = function (r, g, b, o) { + r = math.round(r * 255); + g = math.round(g * 255); + b = math.round(b * 255); + var rgb = { + r: r, + g: g, + b: b, + opacity: is(o, "finite") ? o : 1, + hex: Snap.rgb(r, g, b), + toString: rgbtoString + }; + is(o, "finite") && (rgb.opacity = o); + return rgb; +}; +/*\ + * Snap.color + [ method ] + ** + * Parses the color string and returns an object featuring the color's component values + - clr (string) color string in one of the supported formats (see @Snap.getRGB) + = (object) Combined RGB/HSB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #••••••, + o error (boolean) `true` if string can't be parsed, + o h (number) hue, + o s (number) saturation, + o v (number) value (brightness), + o l (number) lightness + o } +\*/ +Snap.color = function (clr) { + var rgb; + if (is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = Snap.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else if (is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = Snap.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.opacity = 1; + clr.hex = rgb.hex; + } else { + if (is(clr, "string")) { + clr = Snap.getRGB(clr); + } + if (is(clr, "object") && "r" in clr && "g" in clr && "b" in clr && !("error" in clr)) { + rgb = Snap.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = Snap.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + clr.error = 1; + } + } + clr.toString = rgbtoString; + return clr; +}; +/*\ + * Snap.hsb2rgb + [ method ] + ** + * Converts HSB values to an RGB object + - h (number) hue + - s (number) saturation + - v (number) value or brightness + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsb2rgb = function (h, s, v, o) { + if (is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + o = h.o; + h = h.h; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.hsl2rgb + [ method ] + ** + * Converts HSL values to an RGB object + - h (number) hue + - s (number) saturation + - l (number) luminosity + = (object) RGB object in the following format: + o { + o r (number) red, + o g (number) green, + o b (number) blue, + o hex (string) color in HTML/CSS format: #•••••• + o } +\*/ +Snap.hsl2rgb = function (h, s, l, o) { + if (is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); +}; +/*\ + * Snap.rgb2hsb + [ method ] + ** + * Converts RGB values to an HSB object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSB object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o b (number) brightness + o } +\*/ +Snap.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; +}; +/*\ + * Snap.rgb2hsl + [ method ] + ** + * Converts RGB values to an HSL object + - r (number) red + - g (number) green + - b (number) blue + = (object) HSL object in the following format: + o { + o h (number) hue, + o s (number) saturation, + o l (number) luminosity + o } +\*/ +Snap.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; +}; + +// Transformations +/*\ + * Snap.parsePathString + [ method ] + ** + * Utility method + ** + * Parses given path string into an array of arrays of path segments + - pathString (string|array) path string or array of segments (in the last case it is returned straight away) + = (array) array of segments +\*/ +Snap.parsePathString = function (pathString) { + if (!pathString) { + return null; + } + var pth = Snap.path(pathString); + if (pth.arr) { + return Snap.path.clone(pth.arr); + } + + var paramCounts = {a: 7, c: 6, o: 2, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, u: 3, z: 0}, + data = []; + if (is(pathString, "array") && is(pathString[0], "array")) { // rough assumption + data = Snap.path.clone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b].concat(params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "o" && params.length == 1) { + data.push([b, params[0]]); + } + if (name == "r") { + data.push([b].concat(params)); + } else while (params.length >= paramCounts[name]) { + data.push([b].concat(params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = Snap.path.toString; + pth.arr = Snap.path.clone(data); + return data; +}; +/*\ + * Snap.parseTransformString + [ method ] + ** + * Utility method + ** + * Parses given transform string into an array of transformations + - TString (string|array) transform string or array of transformations (in the last case it is returned straight away) + = (array) array of transformations +\*/ +var parseTransformString = Snap.parseTransformString = function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (is(TString, "array") && is(TString[0], "array")) { // rough assumption + data = Snap.path.clone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b].concat(params)); + }); + } + data.toString = Snap.path.toString; + return data; +}; +function svgTransform2string(tstr) { + var res = []; + tstr = tstr.replace(/(?:^|\s)(\w+)\(([^)]+)\)/g, function (all, name, params) { + params = params.split(/\s*,\s*|\s+/); + if (name == "rotate" && params.length == 1) { + params.push(0, 0); + } + if (name == "scale") { + if (params.length > 2) { + params = params.slice(0, 2); + } else if (params.length == 2) { + params.push(0, 0); + } + if (params.length == 1) { + params.push(params[0], 0, 0); + } + } + if (name == "skewX") { + res.push(["m", 1, 0, math.tan(rad(params[0])), 1, 0, 0]); + } else if (name == "skewY") { + res.push(["m", 1, math.tan(rad(params[0])), 0, 1, 0, 0]); + } else { + res.push([name.charAt(0)].concat(params)); + } + return all; + }); + return res; +} +Snap._.svgTransform2string = svgTransform2string; +Snap._.rgTransform = /^[a-z][\s]*-?\.?\d/i; +function transform2matrix(tstr, bbox) { + var tdata = parseTransformString(tstr), + m = new Snap.Matrix; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 2){ + m.translate(t[1], 0); + } else if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || bbox; + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || bbox; + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.scale(t[1], t[1], x2, y2); + } else { + m.scale(t[1], t[1], t[2], t[3]); + } + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + } + } + return m; +} +Snap._.transform2matrix = transform2matrix; +Snap._unit2px = unit2px; +var contains = glob.doc.contains || glob.doc.compareDocumentPosition ? + function (a, b) { + var adown = a.nodeType == 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a == bup || !!(bup && bup.nodeType == 1 && ( + adown.contains ? + adown.contains(bup) : + a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16 + )); + } : + function (a, b) { + if (b) { + while (b) { + b = b.parentNode; + if (b == a) { + return true; + } + } + } + return false; + }; +function getSomeDefs(el) { + var p = (el.node.ownerSVGElement && wrap(el.node.ownerSVGElement)) || + (el.node.parentNode && wrap(el.node.parentNode)) || + Snap.select("svg") || + Snap(0, 0), + pdefs = p.select("defs"), + defs = pdefs == null ? false : pdefs.node; + if (!defs) { + defs = make("defs", p.node).node; + } + return defs; +} +function getSomeSVG(el) { + return el.node.ownerSVGElement && wrap(el.node.ownerSVGElement) || Snap.select("svg"); +} +Snap._.getSomeDefs = getSomeDefs; +Snap._.getSomeSVG = getSomeSVG; +function unit2px(el, name, value) { + var svg = getSomeSVG(el).node, + out = {}, + mgr = svg.querySelector(".svg---mgr"); + if (!mgr) { + mgr = $("rect"); + $(mgr, {x: -9e9, y: -9e9, width: 10, height: 10, "class": "svg---mgr", fill: "none"}); + svg.appendChild(mgr); + } + function getW(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {width: val}); + try { + return mgr.getBBox().width; + } catch (e) { + return 0; + } + } + function getH(val) { + if (val == null) { + return E; + } + if (val == +val) { + return val; + } + $(mgr, {height: val}); + try { + return mgr.getBBox().height; + } catch (e) { + return 0; + } + } + function set(nam, f) { + if (name == null) { + out[nam] = f(el.attr(nam) || 0); + } else if (nam == name) { + out = f(value == null ? el.attr(nam) || 0 : value); + } + } + switch (el.type) { + case "rect": + set("rx", getW); + set("ry", getH); + case "image": + set("width", getW); + set("height", getH); + case "text": + set("x", getW); + set("y", getH); + break; + case "circle": + set("cx", getW); + set("cy", getH); + set("r", getW); + break; + case "ellipse": + set("cx", getW); + set("cy", getH); + set("rx", getW); + set("ry", getH); + break; + case "line": + set("x1", getW); + set("x2", getW); + set("y1", getH); + set("y2", getH); + break; + case "marker": + set("refX", getW); + set("markerWidth", getW); + set("refY", getH); + set("markerHeight", getH); + break; + case "radialGradient": + set("fx", getW); + set("fy", getH); + break; + case "tspan": + set("dx", getW); + set("dy", getH); + break; + default: + set(name, getW); + } + svg.removeChild(mgr); + return out; +} +/*\ + * Snap.select + [ method ] + ** + * Wraps a DOM element specified by CSS selector as @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.select = function (query) { + query = Str(query).replace(/([^\\]):/g, "$1\\:"); + return wrap(glob.doc.querySelector(query)); +}; +/*\ + * Snap.selectAll + [ method ] + ** + * Wraps DOM elements specified by CSS selector as set or array of @Element + - query (string) CSS selector of the element + = (Element) the current element +\*/ +Snap.selectAll = function (query) { + var nodelist = glob.doc.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; +}; + +function add2group(list) { + if (!is(list, "array")) { + list = Array.prototype.slice.call(arguments, 0); + } + var i = 0, + j = 0, + node = this.node; + while (this[i]) delete this[i++]; + for (i = 0; i < list.length; i++) { + if (list[i].type == "set") { + list[i].forEach(function (el) { + node.appendChild(el.node); + }); + } else { + node.appendChild(list[i].node); + } + } + var children = node.childNodes; + for (i = 0; i < children.length; i++) { + this[j++] = wrap(children[i]); + } + return this; +} +// Hub garbage collector every 10s +setInterval(function () { + for (var key in hub) if (hub[has](key)) { + var el = hub[key], + node = el.node; + if (el.type != "svg" && !node.ownerSVGElement || el.type == "svg" && (!node.parentNode || "ownerSVGElement" in node.parentNode && !node.ownerSVGElement)) { + delete hub[key]; + } + } +}, 1e4); +function Element(el) { + if (el.snap in hub) { + return hub[el.snap]; + } + var svg; + try { + svg = el.ownerSVGElement; + } catch(e) {} + /*\ + * Element.node + [ property (object) ] + ** + * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. + > Usage + | // draw a circle at coordinate 10,10 with radius of 10 + | var c = paper.circle(10, 10, 10); + | c.node.onclick = function () { + | c.attr("fill", "red"); + | }; + \*/ + this.node = el; + if (svg) { + this.paper = new Paper(svg); + } + /*\ + * Element.type + [ property (string) ] + ** + * SVG tag name of the given element. + \*/ + this.type = el.tagName || el.nodeName; + var id = this.id = ID(this); + this.anims = {}; + this._ = { + transform: [] + }; + el.snap = id; + hub[id] = this; + if (this.type == "g") { + this.add = add2group; + } + if (this.type in {g: 1, mask: 1, pattern: 1, symbol: 1}) { + for (var method in Paper.prototype) if (Paper.prototype[has](method)) { + this[method] = Paper.prototype[method]; + } + } +} + /*\ + * Element.attr + [ method ] + ** + * Gets or sets given attributes of the element. + ** + - params (object) contains key-value pairs of attributes you want to set + * or + - param (string) name of the attribute + = (Element) the current element + * or + = (string) value of attribute + > Usage + | el.attr({ + | fill: "#fc0", + | stroke: "#000", + | strokeWidth: 2, // CamelCase... + | "fill-opacity": 0.5, // or dash-separated names + | width: "*=2" // prefixed values + | }); + | console.log(el.attr("fill")); // #fc0 + * Prefixed values in format `"+=10"` supported. All four operations + * (`+`, `-`, `*` and `/`) could be used. Optionally you can use units for `+` + * and `-`: `"+=2em"`. + \*/ + Element.prototype.attr = function (params, value) { + var el = this, + node = el.node; + if (!params) { + if (node.nodeType != 1) { + return { + text: node.nodeValue + }; + } + var attr = node.attributes, + out = {}; + for (var i = 0, ii = attr.length; i < ii; i++) { + out[attr[i].nodeName] = attr[i].nodeValue; + } + return out; + } + if (is(params, "string")) { + if (arguments.length > 1) { + var json = {}; + json[params] = value; + params = json; + } else { + return eve("snap.util.getattr." + params, el).firstDefined(); + } + } + for (var att in params) { + if (params[has](att)) { + eve("snap.util.attr." + att, el, params[att]); + } + } + return el; + }; +/*\ + * Snap.parse + [ method ] + ** + * Parses SVG fragment and converts it into a @Fragment + ** + - svg (string) SVG string + = (Fragment) the @Fragment +\*/ +Snap.parse = function (svg) { + var f = glob.doc.createDocumentFragment(), + full = true, + div = glob.doc.createElement("div"); + svg = Str(svg); + if (!svg.match(/^\s*<\s*svg(?:\s|>)/)) { + svg = "<svg>" + svg + "</svg>"; + full = false; + } + div.innerHTML = svg; + svg = div.getElementsByTagName("svg")[0]; + if (svg) { + if (full) { + f = svg; + } else { + while (svg.firstChild) { + f.appendChild(svg.firstChild); + } + } + } + return new Fragment(f); +}; +function Fragment(frag) { + this.node = frag; +} +/*\ + * Snap.fragment + [ method ] + ** + * Creates a DOM fragment from a given list of elements or strings + ** + - varargs (…) SVG string + = (Fragment) the @Fragment +\*/ +Snap.fragment = function () { + var args = Array.prototype.slice.call(arguments, 0), + f = glob.doc.createDocumentFragment(); + for (var i = 0, ii = args.length; i < ii; i++) { + var item = args[i]; + if (item.node && item.node.nodeType) { + f.appendChild(item.node); + } + if (item.nodeType) { + f.appendChild(item); + } + if (typeof item == "string") { + f.appendChild(Snap.parse(item).node); + } + } + return new Fragment(f); +}; + +function make(name, parent) { + var res = $(name); + parent.appendChild(res); + var el = wrap(res); + return el; +} +function Paper(w, h) { + var res, + desc, + defs, + proto = Paper.prototype; + if (w && w.tagName == "svg") { + if (w.snap in hub) { + return hub[w.snap]; + } + var doc = w.ownerDocument; + res = new Element(w); + desc = w.getElementsByTagName("desc")[0]; + defs = w.getElementsByTagName("defs")[0]; + if (!desc) { + desc = $("desc"); + desc.appendChild(doc.createTextNode("Created with Snap")); + res.node.appendChild(desc); + } + if (!defs) { + defs = $("defs"); + res.node.appendChild(defs); + } + res.defs = defs; + for (var key in proto) if (proto[has](key)) { + res[key] = proto[key]; + } + res.paper = res.root = res; + } else { + res = make("svg", glob.doc.body); + $(res.node, { + height: h, + version: 1.1, + width: w, + xmlns: xmlns + }); + } + return res; +} +function wrap(dom) { + if (!dom) { + return dom; + } + if (dom instanceof Element || dom instanceof Fragment) { + return dom; + } + if (dom.tagName && dom.tagName.toLowerCase() == "svg") { + return new Paper(dom); + } + if (dom.tagName && dom.tagName.toLowerCase() == "object" && dom.type == "image/svg+xml") { + return new Paper(dom.contentDocument.getElementsByTagName("svg")[0]); + } + return new Element(dom); +} + +Snap._.make = make; +Snap._.wrap = wrap; +/*\ + * Paper.el + [ method ] + ** + * Creates an element on paper with a given name and no attributes + ** + - name (string) tag name + - attr (object) attributes + = (Element) the current element + > Usage + | var c = paper.circle(10, 10, 10); // is the same as... + | var c = paper.el("circle").attr({ + | cx: 10, + | cy: 10, + | r: 10 + | }); + | // and the same as + | var c = paper.el("circle", { + | cx: 10, + | cy: 10, + | r: 10 + | }); +\*/ +Paper.prototype.el = function (name, attr) { + var el = make(name, this.node); + attr && el.attr(attr); + return el; +}; +/*\ + * Element.children + [ method ] + ** + * Returns array of all the children of the element. + = (array) array of Elements +\*/ +Element.prototype.children = function () { + var out = [], + ch = this.node.childNodes; + for (var i = 0, ii = ch.length; i < ii; i++) { + out[i] = Snap(ch[i]); + } + return out; +}; +function jsonFiller(root, o) { + for (var i = 0, ii = root.length; i < ii; i++) { + var item = { + type: root[i].type, + attr: root[i].attr() + }, + children = root[i].children(); + o.push(item); + if (children.length) { + jsonFiller(children, item.childNodes = []); + } + } +} +/*\ + * Element.toJSON + [ method ] + ** + * Returns object representation of the given element and all its children. + = (object) in format + o { + o type (string) this.type, + o attr (object) attributes map, + o childNodes (array) optional array of children in the same format + o } +\*/ +Element.prototype.toJSON = function () { + var out = []; + jsonFiller([this], out); + return out[0]; +}; +// default +eve.on("snap.util.getattr", function () { + var att = eve.nt(); + att = att.substring(att.lastIndexOf(".") + 1); + var css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + return this.node.ownerDocument.defaultView.getComputedStyle(this.node, null).getPropertyValue(css); + } else { + return $(this.node, att); + } +}); +var cssAttr = { + "alignment-baseline": 0, + "baseline-shift": 0, + "clip": 0, + "clip-path": 0, + "clip-rule": 0, + "color": 0, + "color-interpolation": 0, + "color-interpolation-filters": 0, + "color-profile": 0, + "color-rendering": 0, + "cursor": 0, + "direction": 0, + "display": 0, + "dominant-baseline": 0, + "enable-background": 0, + "fill": 0, + "fill-opacity": 0, + "fill-rule": 0, + "filter": 0, + "flood-color": 0, + "flood-opacity": 0, + "font": 0, + "font-family": 0, + "font-size": 0, + "font-size-adjust": 0, + "font-stretch": 0, + "font-style": 0, + "font-variant": 0, + "font-weight": 0, + "glyph-orientation-horizontal": 0, + "glyph-orientation-vertical": 0, + "image-rendering": 0, + "kerning": 0, + "letter-spacing": 0, + "lighting-color": 0, + "marker": 0, + "marker-end": 0, + "marker-mid": 0, + "marker-start": 0, + "mask": 0, + "opacity": 0, + "overflow": 0, + "pointer-events": 0, + "shape-rendering": 0, + "stop-color": 0, + "stop-opacity": 0, + "stroke": 0, + "stroke-dasharray": 0, + "stroke-dashoffset": 0, + "stroke-linecap": 0, + "stroke-linejoin": 0, + "stroke-miterlimit": 0, + "stroke-opacity": 0, + "stroke-width": 0, + "text-anchor": 0, + "text-decoration": 0, + "text-rendering": 0, + "unicode-bidi": 0, + "visibility": 0, + "word-spacing": 0, + "writing-mode": 0 +}; + +eve.on("snap.util.attr", function (value) { + var att = eve.nt(), + attr = {}; + att = att.substring(att.lastIndexOf(".") + 1); + attr[att] = value; + var style = att.replace(/-(\w)/gi, function (all, letter) { + return letter.toUpperCase(); + }), + css = att.replace(/[A-Z]/g, function (letter) { + return "-" + letter.toLowerCase(); + }); + if (cssAttr[has](css)) { + this.node.style[style] = value == null ? E : value; + } else { + $(this.node, attr); + } +}); +(function (proto) {}(Paper.prototype)); + +// simple ajax +/*\ + * Snap.ajax + [ method ] + ** + * Simple implementation of Ajax + ** + - url (string) URL + - postData (object|string) data for post request + - callback (function) callback + - scope (object) #optional scope of callback + * or + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback + = (XMLHttpRequest) the XMLHttpRequest object, just in case +\*/ +Snap.ajax = function (url, postData, callback, scope){ + var req = new XMLHttpRequest, + id = ID(); + if (req) { + if (is(postData, "function")) { + scope = callback; + callback = postData; + postData = null; + } else if (is(postData, "object")) { + var pd = []; + for (var key in postData) if (postData.hasOwnProperty(key)) { + pd.push(encodeURIComponent(key) + "=" + encodeURIComponent(postData[key])); + } + postData = pd.join("&"); + } + req.open((postData ? "POST" : "GET"), url, true); + if (postData) { + req.setRequestHeader("X-Requested-With", "XMLHttpRequest"); + req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + } + if (callback) { + eve.once("snap.ajax." + id + ".0", callback); + eve.once("snap.ajax." + id + ".200", callback); + eve.once("snap.ajax." + id + ".304", callback); + } + req.onreadystatechange = function() { + if (req.readyState != 4) return; + eve("snap.ajax." + id + "." + req.status, scope, req); + }; + if (req.readyState == 4) { + return req; + } + req.send(postData); + return req; + } +}; +/*\ + * Snap.load + [ method ] + ** + * Loads external SVG file as a @Fragment (see @Snap.ajax for more advanced AJAX) + ** + - url (string) URL + - callback (function) callback + - scope (object) #optional scope of callback +\*/ +Snap.load = function (url, callback, scope) { + Snap.ajax(url, function (req) { + var f = Snap.parse(req.responseText); + scope ? callback.call(scope, f) : callback(f); + }); +}; +var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; +}; +/*\ + * Snap.getElementByPoint + [ method ] + ** + * Returns you topmost element under given point. + ** + = (object) Snap element object + - x (number) x coordinate from the top left corner of the window + - y (number) y coordinate from the top left corner of the window + > Usage + | Snap.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); +\*/ +Snap.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = glob.doc.elementFromPoint(x, y); + if (glob.win.opera && target.tagName == "svg") { + var so = getOffset(target), + sr = target.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = target.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + return wrap(target); +}; +/*\ + * Snap.plugin + [ method ] + ** + * Let you write plugins. You pass in a function with five arguments, like this: + | Snap.plugin(function (Snap, Element, Paper, global, Fragment) { + | Snap.newmethod = function () {}; + | Element.prototype.newmethod = function () {}; + | Paper.prototype.newmethod = function () {}; + | }); + * Inside the function you have access to all main objects (and their + * prototypes). This allow you to extend anything you want. + ** + - f (function) your plugin body +\*/ +Snap.plugin = function (f) { + f(Snap, Element, Paper, glob, Fragment); +}; +glob.win.Snap = Snap; +return Snap; +}(window || this)); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var elproto = Element.prototype, + is = Snap.is, + Str = String, + unit2px = Snap._unit2px, + $ = Snap._.$, + make = Snap._.make, + getSomeDefs = Snap._.getSomeDefs, + has = "hasOwnProperty", + wrap = Snap._.wrap; + /*\ + * Element.getBBox + [ method ] + ** + * Returns the bounding box descriptor for the given element + ** + = (object) bounding box descriptor: + o { + o cx: (number) x of the center, + o cy: (number) x of the center, + o h: (number) height, + o height: (number) height, + o path: (string) path command for the box, + o r0: (number) radius of a circle that fully encloses the box, + o r1: (number) radius of the smallest circle that can be enclosed, + o r2: (number) radius of the largest circle that can be enclosed, + o vb: (string) box as a viewbox command, + o w: (number) width, + o width: (number) width, + o x2: (number) x of the right side, + o x: (number) x of the left side, + o y2: (number) y of the bottom edge, + o y: (number) y of the top edge + o } + \*/ + elproto.getBBox = function (isWithoutTransform) { + if (!Snap.Matrix || !Snap.path) { + return this.node.getBBox(); + } + var el = this, + m = new Snap.Matrix; + if (el.removed) { + return Snap._.box(); + } + while (el.type == "use") { + if (!isWithoutTransform) { + m = m.add(el.transform().localMatrix.translate(el.attr("x") || 0, el.attr("y") || 0)); + } + if (el.original) { + el = el.original; + } else { + var href = el.attr("xlink:href"); + el = el.original = el.node.ownerDocument.getElementById(href.substring(href.indexOf("#") + 1)); + } + } + var _ = el._, + pathfinder = Snap.path.get[el.type] || Snap.path.get.deflt; + try { + if (isWithoutTransform) { + _.bboxwt = pathfinder ? Snap.path.getBBox(el.realPath = pathfinder(el)) : Snap._.box(el.node.getBBox()); + return Snap._.box(_.bboxwt); + } else { + el.realPath = pathfinder(el); + el.matrix = el.transform().localMatrix; + _.bbox = Snap.path.getBBox(Snap.path.map(el.realPath, m.add(el.matrix))); + return Snap._.box(_.bbox); + } + } catch (e) { + // Firefox doesn’t give you bbox of hidden element + return Snap._.box(); + } + }; + var propString = function () { + return this.string; + }; + function extractTransform(el, tstr) { + if (tstr == null) { + var doReturn = true; + if (el.type == "linearGradient" || el.type == "radialGradient") { + tstr = el.node.getAttribute("gradientTransform"); + } else if (el.type == "pattern") { + tstr = el.node.getAttribute("patternTransform"); + } else { + tstr = el.node.getAttribute("transform"); + } + if (!tstr) { + return new Snap.Matrix; + } + tstr = Snap._.svgTransform2string(tstr); + } else { + if (!Snap._.rgTransform.test(tstr)) { + tstr = Snap._.svgTransform2string(tstr); + } else { + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || ""); + } + if (is(tstr, "array")) { + tstr = Snap.path ? Snap.path.toString.call(tstr) : Str(tstr); + } + el._.transform = tstr; + } + var m = Snap._.transform2matrix(tstr, el.getBBox(1)); + if (doReturn) { + return m; + } else { + el.matrix = m; + } + } + /*\ + * Element.transform + [ method ] + ** + * Gets or sets transformation of the element + ** + - tstr (string) transform string in Snap or SVG format + = (Element) the current element + * or + = (object) transformation descriptor: + o { + o string (string) transform string, + o globalMatrix (Matrix) matrix of all transformations applied to element or its parents, + o localMatrix (Matrix) matrix of transformations applied only to the element, + o diffMatrix (Matrix) matrix of difference between global and local transformations, + o global (string) global transformation as string, + o local (string) local transformation as string, + o toString (function) returns `string` property + o } + \*/ + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + var papa = this, + global = new Snap.Matrix(this.node.getCTM()), + local = extractTransform(this), + ms = [local], + m = new Snap.Matrix, + i, + localString = local.toTransformString(), + string = Str(local) == Str(this.matrix) ? + Str(_.transform) : localString; + while (papa.type != "svg" && (papa = papa.parent())) { + ms.push(extractTransform(papa)); + } + i = ms.length; + while (i--) { + m.add(ms[i]); + } + return { + string: string, + globalMatrix: global, + totalMatrix: m, + localMatrix: local, + diffMatrix: global.clone().add(local.invert()), + global: global.toTransformString(), + total: m.toTransformString(), + local: localString, + toString: propString + }; + } + if (tstr instanceof Snap.Matrix) { + this.matrix = tstr; + this._.transform = tstr.toTransformString(); + } else { + extractTransform(this, tstr); + } + + if (this.node) { + if (this.type == "linearGradient" || this.type == "radialGradient") { + $(this.node, {gradientTransform: this.matrix}); + } else if (this.type == "pattern") { + $(this.node, {patternTransform: this.matrix}); + } else { + $(this.node, {transform: this.matrix}); + } + } + + return this; + }; + /*\ + * Element.parent + [ method ] + ** + * Returns the element's parent + ** + = (Element) the parent element + \*/ + elproto.parent = function () { + return wrap(this.node.parentNode); + }; + /*\ + * Element.append + [ method ] + ** + * Appends the given element to current one + ** + - el (Element|Set) element to append + = (Element) the parent element + \*/ + /*\ + * Element.add + [ method ] + ** + * See @Element.append + \*/ + elproto.append = elproto.add = function (el) { + if (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + it.add(el); + }); + return this; + } + el = wrap(el); + this.node.appendChild(el.node); + el.paper = this.paper; + } + return this; + }; + /*\ + * Element.appendTo + [ method ] + ** + * Appends the current element to the given one + ** + - el (Element) parent element to append to + = (Element) the child element + \*/ + elproto.appendTo = function (el) { + if (el) { + el = wrap(el); + el.append(this); + } + return this; + }; + /*\ + * Element.prepend + [ method ] + ** + * Prepends the given element to the current one + ** + - el (Element) element to prepend + = (Element) the parent element + \*/ + elproto.prepend = function (el) { + if (el) { + if (el.type == "set") { + var it = this, + first; + el.forEach(function (el) { + if (first) { + first.after(el); + } else { + it.prepend(el); + } + first = el; + }); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.insertBefore(el.node, this.node.firstChild); + this.add && this.add(); + el.paper = this.paper; + this.parent() && this.parent().add(); + parent && parent.add(); + } + return this; + }; + /*\ + * Element.prependTo + [ method ] + ** + * Prepends the current element to the given one + ** + - el (Element) parent element to prepend to + = (Element) the child element + \*/ + elproto.prependTo = function (el) { + el = wrap(el); + el.prepend(this); + return this; + }; + /*\ + * Element.before + [ method ] + ** + * Inserts given element before the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.before = function (el) { + if (el.type == "set") { + var it = this; + el.forEach(function (el) { + var parent = el.parent(); + it.node.parentNode.insertBefore(el.node, it.node); + parent && parent.add(); + }); + this.parent().add(); + return this; + } + el = wrap(el); + var parent = el.parent(); + this.node.parentNode.insertBefore(el.node, this.node); + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.after + [ method ] + ** + * Inserts given element after the current one + ** + - el (Element) element to insert + = (Element) the parent element + \*/ + elproto.after = function (el) { + el = wrap(el); + var parent = el.parent(); + if (this.node.nextSibling) { + this.node.parentNode.insertBefore(el.node, this.node.nextSibling); + } else { + this.node.parentNode.appendChild(el.node); + } + this.parent() && this.parent().add(); + parent && parent.add(); + el.paper = this.paper; + return this; + }; + /*\ + * Element.insertBefore + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertBefore = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.insertAfter + [ method ] + ** + * Inserts the element after the given one + ** + - el (Element) element next to whom insert to + = (Element) the parent element + \*/ + elproto.insertAfter = function (el) { + el = wrap(el); + var parent = this.parent(); + el.node.parentNode.insertBefore(this.node, el.node.nextSibling); + this.paper = el.paper; + parent && parent.add(); + el.parent() && el.parent().add(); + return this; + }; + /*\ + * Element.remove + [ method ] + ** + * Removes element from the DOM + = (Element) the detached element + \*/ + elproto.remove = function () { + var parent = this.parent(); + this.node.parentNode && this.node.parentNode.removeChild(this.node); + delete this.paper; + this.removed = true; + parent && parent.add(); + return this; + }; + /*\ + * Element.select + [ method ] + ** + * Gathers the nested @Element matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Element) result of query selection + \*/ + elproto.select = function (query) { + return wrap(this.node.querySelector(query)); + }; + /*\ + * Element.selectAll + [ method ] + ** + * Gathers nested @Element objects matching the given set of CSS selectors + ** + - query (string) CSS selector + = (Set|array) result of query selection + \*/ + elproto.selectAll = function (query) { + var nodelist = this.node.querySelectorAll(query), + set = (Snap.set || Array)(); + for (var i = 0; i < nodelist.length; i++) { + set.push(wrap(nodelist[i])); + } + return set; + }; + /*\ + * Element.asPX + [ method ] + ** + * Returns given attribute of the element as a `px` value (not %, em, etc.) + ** + - attr (string) attribute name + - value (string) #optional attribute value + = (Element) result of query selection + \*/ + elproto.asPX = function (attr, value) { + if (value == null) { + value = this.attr(attr); + } + return +unit2px(this, attr, value); + }; + // SIERRA Element.use(): I suggest adding a note about how to access the original element the returned <use> instantiates. It's a part of SVG with which ordinary web developers may be least familiar. + /*\ + * Element.use + [ method ] + ** + * Creates a `<use>` element linked to the current element + ** + = (Element) the `<use>` element + \*/ + elproto.use = function () { + var use, + id = this.node.id; + if (!id) { + id = this.id; + $(this.node, { + id: id + }); + } + if (this.type == "linearGradient" || this.type == "radialGradient" || + this.type == "pattern") { + use = make(this.type, this.node.parentNode); + } else { + use = make("use", this.node.parentNode); + } + $(use.node, { + "xlink:href": "#" + id + }); + use.original = this; + return use; + }; + function fixids(el) { + var els = el.selectAll("*"), + it, + url = /^\s*url\(("|'|)(.*)\1\)\s*$/, + ids = [], + uses = {}; + function urltest(it, name) { + var val = $(it.node, name); + val = val && val.match(url); + val = val && val[2]; + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + var attr = {}; + attr[name] = URL(id); + $(it.node, attr); + }); + } + } + function linktest(it) { + var val = $(it.node, "xlink:href"); + if (val && val.charAt() == "#") { + val = val.substring(1); + } else { + return; + } + if (val) { + uses[val] = (uses[val] || []).concat(function (id) { + it.attr("xlink:href", "#" + id); + }); + } + } + for (var i = 0, ii = els.length; i < ii; i++) { + it = els[i]; + urltest(it, "fill"); + urltest(it, "stroke"); + urltest(it, "filter"); + urltest(it, "mask"); + urltest(it, "clip-path"); + linktest(it); + var oldid = $(it.node, "id"); + if (oldid) { + $(it.node, {id: it.id}); + ids.push({ + old: oldid, + id: it.id + }); + } + } + for (i = 0, ii = ids.length; i < ii; i++) { + var fs = uses[ids[i].old]; + if (fs) { + for (var j = 0, jj = fs.length; j < jj; j++) { + fs[j](ids[i].id); + } + } + } + } + /*\ + * Element.clone + [ method ] + ** + * Creates a clone of the element and inserts it after the element + ** + = (Element) the clone + \*/ + elproto.clone = function () { + var clone = wrap(this.node.cloneNode(true)); + if ($(clone.node, "id")) { + $(clone.node, {id: clone.id}); + } + fixids(clone); + clone.insertAfter(this); + return clone; + }; + /*\ + * Element.toDefs + [ method ] + ** + * Moves element to the shared `<defs>` area + ** + = (Element) the element + \*/ + elproto.toDefs = function () { + var defs = getSomeDefs(this); + defs.appendChild(this.node); + return this; + }; + /*\ + * Element.toPattern + [ method ] + ** + * Creates a `<pattern>` element from the current element + ** + * To create a pattern you have to specify the pattern rect: + - x (string|number) + - y (string|number) + - width (string|number) + - height (string|number) + = (Element) the `<pattern>` element + * You can use pattern later on as an argument for `fill` attribute: + | var p = paper.path("M10-5-10,15M15,0,0,15M0-5-20,15").attr({ + | fill: "none", + | stroke: "#bada55", + | strokeWidth: 5 + | }).pattern(0, 0, 10, 10), + | c = paper.circle(200, 200, 100); + | c.attr({ + | fill: p + | }); + \*/ + elproto.pattern = elproto.toPattern = function (x, y, width, height) { + var p = make("pattern", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + $(p.node, { + x: x, + y: y, + width: width, + height: height, + patternUnits: "userSpaceOnUse", + id: p.id, + viewBox: [x, y, width, height].join(" ") + }); + p.node.appendChild(this.node); + return p; + }; +// SIERRA Element.marker(): clarify what a reference point is. E.g., helps you offset the object from its edge such as when centering it over a path. +// SIERRA Element.marker(): I suggest the method should accept default reference point values. Perhaps centered with (refX = width/2) and (refY = height/2)? Also, couldn't it assume the element's current _width_ and _height_? And please specify what _x_ and _y_ mean: offsets? If so, from where? Couldn't they also be assigned default values? + /*\ + * Element.marker + [ method ] + ** + * Creates a `<marker>` element from the current element + ** + * To create a marker you have to specify the bounding rect and reference point: + - x (number) + - y (number) + - width (number) + - height (number) + - refX (number) + - refY (number) + = (Element) the `<marker>` element + * You can specify the marker later as an argument for `marker-start`, `marker-end`, `marker-mid`, and `marker` attributes. The `marker` attribute places the marker at every point along the path, and `marker-mid` places them at every point except the start and end. + \*/ + // TODO add usage for markers + elproto.marker = function (x, y, width, height, refX, refY) { + var p = make("marker", getSomeDefs(this)); + if (x == null) { + x = this.getBBox(); + } + if (is(x, "object") && "x" in x) { + y = x.y; + width = x.width; + height = x.height; + refX = x.refX || x.cx; + refY = x.refY || x.cy; + x = x.x; + } + $(p.node, { + viewBox: [x, y, width, height].join(" "), + markerWidth: width, + markerHeight: height, + orient: "auto", + refX: refX || 0, + refY: refY || 0, + id: p.id + }); + p.node.appendChild(this.node); + return p; + }; + // animation + function slice(from, to, f) { + return function (arr) { + var res = arr.slice(from, to); + if (res.length == 1) { + res = res[0]; + } + return f ? f(res) : res; + }; + } + var Animation = function (attr, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + this.attr = attr; + this.dur = ms; + easing && (this.easing = easing); + callback && (this.callback = callback); + }; + Snap._.Animation = Animation; + /*\ + * Snap.animation + [ method ] + ** + * Creates an animation object + ** + - attr (object) attributes of final destination + - duration (number) duration of the animation, in milliseconds + - easing (function) #optional one of easing functions of @mina or custom one + - callback (function) #optional callback function that fires when animation ends + = (object) animation object + \*/ + Snap.animation = function (attr, ms, easing, callback) { + return new Animation(attr, ms, easing, callback); + }; + /*\ + * Element.inAnim + [ method ] + ** + * Returns a set of animations that may be able to manipulate the current element + ** + = (object) in format: + o { + o anim (object) animation object, + o mina (object) @mina object, + o curStatus (number) 0..1 — status of the animation: 0 — just started, 1 — just finished, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + \*/ + elproto.inAnim = function () { + var el = this, + res = []; + for (var id in el.anims) if (el.anims[has](id)) { + (function (a) { + res.push({ + anim: new Animation(a._attrs, a.dur, a.easing, a._callback), + mina: a, + curStatus: a.status(), + status: function (val) { + return a.status(val); + }, + stop: function () { + a.stop(); + } + }); + }(el.anims[id])); + } + return res; + }; + /*\ + * Snap.animate + [ method ] + ** + * Runs generic animation of one number into another with a caring function + ** + - from (number|array) number or array of numbers + - to (number|array) number or array of numbers + - setter (function) caring function that accepts one number argument + - duration (number) duration, in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function to execute when animation ends + = (object) animation object in @mina format + o { + o id (string) animation id, consider it read-only, + o duration (function) gets or sets the duration of the animation, + o easing (function) easing, + o speed (function) gets or sets the speed of the animation, + o status (function) gets or sets the status of the animation, + o stop (function) stops the animation + o } + | var rect = Snap().rect(0, 0, 10, 10); + | Snap.animate(0, 10, function (val) { + | rect.attr({ + | x: val + | }); + | }, 1000); + | // in given context is equivalent to + | rect.animate({x: 10}, 1000); + \*/ + Snap.animate = function (from, to, setter, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + var now = mina.time(), + anim = mina(from, to, now, now + ms, mina.time, setter, easing); + callback && eve.once("mina.finish." + anim.id, callback); + return anim; + }; + /*\ + * Element.stop + [ method ] + ** + * Stops all the animations for the current element + ** + = (Element) the current element + \*/ + elproto.stop = function () { + var anims = this.inAnim(); + for (var i = 0, ii = anims.length; i < ii; i++) { + anims[i].stop(); + } + return this; + }; + /*\ + * Element.animate + [ method ] + ** + * Animates the given attributes of the element + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + = (Element) the current element + \*/ + elproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = attrs.dur; + attrs = attrs.attr; + } + var fkeys = [], tkeys = [], keys = {}, from, to, f, eq, + el = this; + for (var key in attrs) if (attrs[has](key)) { + if (el.equal) { + eq = el.equal(key, Str(attrs[key])); + from = eq.from; + to = eq.to; + f = eq.f; + } else { + from = +el.attr(key); + to = +attrs[key]; + } + var len = is(from, "array") ? from.length : 1; + keys[key] = slice(fkeys.length, fkeys.length + len, f); + fkeys = fkeys.concat(from); + tkeys = tkeys.concat(to); + } + var now = mina.time(), + anim = mina(fkeys, tkeys, now, now + ms, mina.time, function (val) { + var attr = {}; + for (var key in keys) if (keys[has](key)) { + attr[key] = keys[key](val); + } + el.attr(attr); + }, easing); + el.anims[anim.id] = anim; + anim._attrs = attrs; + anim._callback = callback; + eve("snap.animcreated." + el.id, anim); + eve.once("mina.finish." + anim.id, function () { + delete el.anims[anim.id]; + callback && callback.call(el); + }); + eve.once("mina.stop." + anim.id, function () { + delete el.anims[anim.id]; + }); + return el; + }; + var eldata = {}; + /*\ + * Element.data + [ method ] + ** + * Adds or retrieves given value associated with given key. (Don’t confuse + * with `data-` attributes) + * + * See also @Element.removeData + - key (string) key to store data + - value (any) #optional value to store + = (object) @Element + * or, if value is not specified: + = (any) value + > Usage + | for (var i = 0, i < 5, i++) { + | paper.circle(10 + 15 * i, 10, 10) + | .attr({fill: "#000"}) + | .data("i", i) + | .click(function () { + | alert(this.data("i")); + | }); + | } + \*/ + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 0){ + eve("snap.data.get." + this.id, this, data, null); + return data; + } + if (arguments.length == 1) { + if (Snap.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("snap.data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("snap.data.set." + this.id, this, value, key); + return this; + }; + /*\ + * Element.removeData + [ method ] + ** + * Removes value associated with an element by given key. + * If key is not provided, removes all the data of the element. + - key (string) #optional key + = (object) @Element + \*/ + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + /*\ + * Element.outerSVG + [ method ] + ** + * Returns SVG code for the element, equivalent to HTML's `outerHTML`. + * + * See also @Element.innerSVG + = (string) SVG code for the element + \*/ + /*\ + * Element.toString + [ method ] + ** + * See @Element.outerSVG + \*/ + elproto.outerSVG = elproto.toString = toString(1); + /*\ + * Element.innerSVG + [ method ] + ** + * Returns SVG code for the element's contents, equivalent to HTML's `innerHTML` + = (string) SVG code for the element + \*/ + elproto.innerSVG = toString(); + function toString(type) { + return function () { + var res = type ? "<" + this.type : "", + attr = this.node.attributes, + chld = this.node.childNodes; + if (type) { + for (var i = 0, ii = attr.length; i < ii; i++) { + res += " " + attr[i].name + '="' + + attr[i].value.replace(/"/g, '\\"') + '"'; + } + } + if (chld.length) { + type && (res += ">"); + for (i = 0, ii = chld.length; i < ii; i++) { + if (chld[i].nodeType == 3) { + res += chld[i].nodeValue; + } else if (chld[i].nodeType == 1) { + res += wrap(chld[i]).toString(); + } + } + type && (res += "</" + this.type + ">"); + } else { + type && (res += "/>"); + } + return res; + }; + } + elproto.toDataURL = function () { + if (window && window.btoa) { + var bb = this.getBBox(), + svg = Snap.format('<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{width}" height="{height}" viewBox="{x} {y} {width} {height}">{contents}</svg>', { + x: +bb.x.toFixed(3), + y: +bb.y.toFixed(3), + width: +bb.width.toFixed(3), + height: +bb.height.toFixed(3), + contents: this.outerSVG() + }); + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(svg))); + } + }; + /*\ + * Fragment.select + [ method ] + ** + * See @Element.select + \*/ + Fragment.prototype.select = elproto.select; + /*\ + * Fragment.selectAll + [ method ] + ** + * See @Element.selectAll + \*/ + Fragment.prototype.selectAll = elproto.selectAll; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var objectToString = Object.prototype.toString, + Str = String, + math = Math, + E = ""; + function Matrix(a, b, c, d, e, f) { + if (b == null && objectToString.call(a) == "[object SVGMatrix]") { + this.a = a.a; + this.b = a.b; + this.c = a.c; + this.d = a.d; + this.e = a.e; + this.f = a.f; + return; + } + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + /*\ + * Matrix.add + [ method ] + ** + * Adds the given matrix to existing one + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - matrix (object) @Matrix + \*/ + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + return this; + }; + /*\ + * Matrix.invert + [ method ] + ** + * Returns an inverted version of the matrix + = (object) @Matrix + \*/ + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + /*\ + * Matrix.clone + [ method ] + ** + * Returns a copy of the matrix + = (object) @Matrix + \*/ + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + /*\ + * Matrix.translate + [ method ] + ** + * Translate the matrix + - x (number) horizontal offset distance + - y (number) vertical offset distance + \*/ + matrixproto.translate = function (x, y) { + return this.add(1, 0, 0, 1, x, y); + }; + /*\ + * Matrix.scale + [ method ] + ** + * Scales the matrix + - x (number) amount to be scaled, with `1` resulting in no change + - y (number) #optional amount to scale along the vertical axis. (Otherwise `x` applies to both axes.) + - cx (number) #optional horizontal origin point from which to scale + - cy (number) #optional vertical origin point from which to scale + * Default cx, cy is the middle point of the element. + \*/ + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + return this; + }; + /*\ + * Matrix.rotate + [ method ] + ** + * Rotates the matrix + - a (number) angle of rotation, in degrees + - x (number) horizontal origin point from which to rotate + - y (number) vertical origin point from which to rotate + \*/ + matrixproto.rotate = function (a, x, y) { + a = Snap.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + return this.add(1, 0, 0, 1, -x, -y); + }; + /*\ + * Matrix.x + [ method ] + ** + * Returns x coordinate for given point after transformation described by the matrix. See also @Matrix.y + - x (number) + - y (number) + = (number) x + \*/ + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + /*\ + * Matrix.y + [ method ] + ** + * Returns y coordinate for given point after transformation described by the matrix. See also @Matrix.x + - x (number) + - y (number) + = (number) y + \*/ + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + /*\ + * Matrix.determinant + [ method ] + ** + * Finds determinant of the given matrix. + = (number) determinant + \*/ + matrixproto.determinant = function () { + return this.a * this.d - this.b * this.c; + }; + /*\ + * Matrix.split + [ method ] + ** + * Splits matrix into primitive transformations + = (object) in format: + o dx (number) translation by x + o dy (number) translation by y + o scalex (number) scale by x + o scaley (number) scale by y + o shear (number) shear + o rotate (number) rotation in deg + o isSimple (boolean) could it be represented via simple transformations + \*/ + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + if (this.determinant() < 0) { + out.scalex = -out.scalex; + } + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = Snap.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = Snap.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + /*\ + * Matrix.toTransformString + [ method ] + ** + * Returns transform string that represents given matrix + = (string) transform string + \*/ + matrixproto.toTransformString = function (shorter) { + var s = shorter || this.split(); + if (!+s.shear.toFixed(9)) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx || s.dy ? "t" + [+s.dx.toFixed(4), +s.dy.toFixed(4)] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [+s.rotate.toFixed(4), 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + /*\ + * Snap.Matrix + [ method ] + ** + * Matrix constructor, extend on your own risk. + * To create matrices use @Snap.matrix. + \*/ + Snap.Matrix = Matrix; + /*\ + * Snap.matrix + [ method ] + ** + * Utility method + ** + * Returns a matrix based on the given parameters + - a (number) + - b (number) + - c (number) + - d (number) + - e (number) + - f (number) + * or + - svgMatrix (SVGMatrix) + = (object) @Matrix + \*/ + Snap.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var has = "hasOwnProperty", + make = Snap._.make, + wrap = Snap._.wrap, + is = Snap.is, + getSomeDefs = Snap._.getSomeDefs, + reURLValue = /^url\(#?([^)]+)\)$/, + $ = Snap._.$, + URL = Snap.url, + Str = String, + separator = Snap._.separator, + E = ""; + // Attributes event handlers + eve.on("snap.util.attr.mask", function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value.type == "mask") { + var mask = value; + } else { + mask = make("mask", getSomeDefs(this)); + mask.node.appendChild(value.node); + } + !mask.node.id && $(mask.node, { + id: mask.id + }); + $(this.node, { + mask: URL(mask.id) + }); + } + }); + (function (clipIt) { + eve.on("snap.util.attr.clip", clipIt); + eve.on("snap.util.attr.clip-path", clipIt); + eve.on("snap.util.attr.clipPath", clipIt); + }(function (value) { + if (value instanceof Element || value instanceof Fragment) { + eve.stop(); + if (value.type == "clipPath") { + var clip = value; + } else { + clip = make("clipPath", getSomeDefs(this)); + clip.node.appendChild(value.node); + !clip.node.id && $(clip.node, { + id: clip.id + }); + } + $(this.node, { + "clip-path": URL(clip.node.id || clip.id) + }); + } + })); + function fillStroke(name) { + return function (value) { + eve.stop(); + if (value instanceof Fragment && value.node.childNodes.length == 1 && + (value.node.firstChild.tagName == "radialGradient" || + value.node.firstChild.tagName == "linearGradient" || + value.node.firstChild.tagName == "pattern")) { + value = value.node.firstChild; + getSomeDefs(this).appendChild(value); + value = wrap(value); + } + if (value instanceof Element) { + if (value.type == "radialGradient" || value.type == "linearGradient" + || value.type == "pattern") { + if (!value.node.id) { + $(value.node, { + id: value.id + }); + } + var fill = URL(value.node.id); + } else { + fill = value.attr(name); + } + } else { + fill = Snap.color(value); + if (fill.error) { + var grad = Snap(getSomeDefs(this).ownerSVGElement).gradient(value); + if (grad) { + if (!grad.node.id) { + $(grad.node, { + id: grad.id + }); + } + fill = URL(grad.node.id); + } else { + fill = value; + } + } else { + fill = Str(fill); + } + } + var attrs = {}; + attrs[name] = fill; + $(this.node, attrs); + this.node.style[name] = E; + }; + } + eve.on("snap.util.attr.fill", fillStroke("fill")); + eve.on("snap.util.attr.stroke", fillStroke("stroke")); + var gradrg = /^([lr])(?:\(([^)]*)\))?(.*)$/i; + eve.on("snap.util.grad.parse", function parseGrad(string) { + string = Str(string); + var tokens = string.match(gradrg); + if (!tokens) { + return null; + } + var type = tokens[1], + params = tokens[2], + stops = tokens[3]; + params = params.split(/\s*,\s*/).map(function (el) { + return +el == el ? +el : el; + }); + if (params.length == 1 && params[0] == 0) { + params = []; + } + stops = stops.split("-"); + stops = stops.map(function (el) { + el = el.split(":"); + var out = { + color: el[0] + }; + if (el[1]) { + out.offset = parseFloat(el[1]); + } + return out; + }); + return { + type: type, + params: params, + stops: stops + }; + }); + + eve.on("snap.util.attr.d", function (value) { + eve.stop(); + if (is(value, "array") && is(value[0], "array")) { + value = Snap.path.toString.call(value); + } + value = Str(value); + if (value.match(/[ruo]/i)) { + value = Snap.path.toAbsolute(value); + } + $(this.node, {d: value}); + })(-1); + eve.on("snap.util.attr.#text", function (value) { + eve.stop(); + value = Str(value); + var txt = glob.doc.createTextNode(value); + while (this.node.firstChild) { + this.node.removeChild(this.node.firstChild); + } + this.node.appendChild(txt); + })(-1); + eve.on("snap.util.attr.path", function (value) { + eve.stop(); + this.attr({d: value}); + })(-1); + eve.on("snap.util.attr.class", function (value) { + eve.stop(); + this.node.className.baseVal = value; + })(-1); + eve.on("snap.util.attr.viewBox", function (value) { + var vb; + if (is(value, "object") && "x" in value) { + vb = [value.x, value.y, value.width, value.height].join(" "); + } else if (is(value, "array")) { + vb = value.join(" "); + } else { + vb = value; + } + $(this.node, { + viewBox: vb + }); + eve.stop(); + })(-1); + eve.on("snap.util.attr.transform", function (value) { + this.transform(value); + eve.stop(); + })(-1); + eve.on("snap.util.attr.r", function (value) { + if (this.type == "rect") { + eve.stop(); + $(this.node, { + rx: value, + ry: value + }); + } + })(-1); + eve.on("snap.util.attr.textpath", function (value) { + eve.stop(); + if (this.type == "text") { + var id, tp, node; + if (!value && this.textPath) { + tp = this.textPath; + while (tp.node.firstChild) { + this.node.appendChild(tp.node.firstChild); + } + tp.remove(); + delete this.textPath; + return; + } + if (is(value, "string")) { + var defs = getSomeDefs(this), + path = wrap(defs.parentNode).path(value); + defs.appendChild(path.node); + id = path.id; + path.attr({id: id}); + } else { + value = wrap(value); + if (value instanceof Element) { + id = value.attr("id"); + if (!id) { + id = value.id; + value.attr({id: id}); + } + } + } + if (id) { + tp = this.textPath; + node = this.node; + if (tp) { + tp.attr({"xlink:href": "#" + id}); + } else { + tp = $("textPath", { + "xlink:href": "#" + id + }); + while (node.firstChild) { + tp.appendChild(node.firstChild); + } + node.appendChild(tp); + this.textPath = wrap(tp); + } + } + } + })(-1); + eve.on("snap.util.attr.text", function (value) { + if (this.type == "text") { + var i = 0, + node = this.node, + tuner = function (chunk) { + var out = $("tspan"); + if (is(chunk, "array")) { + for (var i = 0; i < chunk.length; i++) { + out.appendChild(tuner(chunk[i])); + } + } else { + out.appendChild(glob.doc.createTextNode(chunk)); + } + out.normalize && out.normalize(); + return out; + }; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var tuned = tuner(value); + while (tuned.firstChild) { + node.appendChild(tuned.firstChild); + } + } + eve.stop(); + })(-1); + function setFontSize(value) { + eve.stop(); + if (value == +value) { + value += "px"; + } + this.node.style.fontSize = value; + } + eve.on("snap.util.attr.fontSize", setFontSize)(-1); + eve.on("snap.util.attr.font-size", setFontSize)(-1); + + + eve.on("snap.util.getattr.transform", function () { + eve.stop(); + return this.transform(); + })(-1); + eve.on("snap.util.getattr.textpath", function () { + eve.stop(); + return this.textPath; + })(-1); + // Markers + (function () { + function getter(end) { + return function () { + eve.stop(); + var style = glob.doc.defaultView.getComputedStyle(this.node, null).getPropertyValue("marker-" + end); + if (style == "none") { + return style; + } else { + return Snap(glob.doc.getElementById(style.match(reURLValue)[1])); + } + }; + } + function setter(end) { + return function (value) { + eve.stop(); + var name = "marker" + end.charAt(0).toUpperCase() + end.substring(1); + if (value == "" || !value) { + this.node.style[name] = "none"; + return; + } + if (value.type == "marker") { + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + } + this.node.style[name] = URL(id); + return; + } + }; + } + eve.on("snap.util.getattr.marker-end", getter("end"))(-1); + eve.on("snap.util.getattr.markerEnd", getter("end"))(-1); + eve.on("snap.util.getattr.marker-start", getter("start"))(-1); + eve.on("snap.util.getattr.markerStart", getter("start"))(-1); + eve.on("snap.util.getattr.marker-mid", getter("mid"))(-1); + eve.on("snap.util.getattr.markerMid", getter("mid"))(-1); + eve.on("snap.util.attr.marker-end", setter("end"))(-1); + eve.on("snap.util.attr.markerEnd", setter("end"))(-1); + eve.on("snap.util.attr.marker-start", setter("start"))(-1); + eve.on("snap.util.attr.markerStart", setter("start"))(-1); + eve.on("snap.util.attr.marker-mid", setter("mid"))(-1); + eve.on("snap.util.attr.markerMid", setter("mid"))(-1); + }()); + eve.on("snap.util.getattr.r", function () { + if (this.type == "rect" && $(this.node, "rx") == $(this.node, "ry")) { + eve.stop(); + return $(this.node, "rx"); + } + })(-1); + function textExtract(node) { + var out = []; + var children = node.childNodes; + for (var i = 0, ii = children.length; i < ii; i++) { + var chi = children[i]; + if (chi.nodeType == 3) { + out.push(chi.nodeValue); + } + if (chi.tagName == "tspan") { + if (chi.childNodes.length == 1 && chi.firstChild.nodeType == 3) { + out.push(chi.firstChild.nodeValue); + } else { + out.push(textExtract(chi)); + } + } + } + return out; + } + eve.on("snap.util.getattr.text", function () { + if (this.type == "text" || this.type == "tspan") { + eve.stop(); + var out = textExtract(this.node); + return out.length == 1 ? out[0] : out; + } + })(-1); + eve.on("snap.util.getattr.#text", function () { + return this.node.textContent; + })(-1); + eve.on("snap.util.getattr.viewBox", function () { + eve.stop(); + var vb = $(this.node, "viewBox"); + if (vb) { + vb = vb.split(separator); + return Snap._.box(+vb[0], +vb[1], +vb[2], +vb[3]); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.points", function () { + var p = $(this.node, "points"); + eve.stop(); + if (p) { + return p.split(separator); + } else { + return; + } + })(-1); + eve.on("snap.util.getattr.path", function () { + var p = $(this.node, "d"); + eve.stop(); + return p; + })(-1); + eve.on("snap.util.getattr.class", function () { + return this.node.className.baseVal; + })(-1); + function getFontSize() { + eve.stop(); + return this.node.style.fontSize; + } + eve.on("snap.util.getattr.fontSize", getFontSize)(-1); + eve.on("snap.util.getattr.font-size", getFontSize)(-1); +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var rgNotSpace = /\S+/g, + rgBadSpace = /[\t\r\n\f]/g, + rgTrim = /(^\s+|\s+$)/g, + Str = String, + elproto = Element.prototype; + /*\ + * Element.addClass + [ method ] + ** + * Adds given class name or list of class names to the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.addClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + + if (classes.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (!~pos) { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.removeClass + [ method ] + ** + * Removes given class name or list of class names from the element. + - value (string) class name or space separated list of class names + ** + = (Element) original element. + \*/ + elproto.removeClass = function (value) { + var classes = Str(value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + if (curClasses.length) { + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + } + return this; + }; + /*\ + * Element.hasClass + [ method ] + ** + * Checks if the element has a given class name in the list of class names applied to it. + - value (string) class name + ** + = (boolean) `true` if the element has given class + \*/ + elproto.hasClass = function (value) { + var elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || []; + return !!~curClasses.indexOf(value); + }; + /*\ + * Element.toggleClass + [ method ] + ** + * Add or remove one or more classes from the element, depending on either + * the class’s presence or the value of the `flag` argument. + - value (string) class name or space separated list of class names + - flag (boolean) value to determine whether the class should be added or removed + ** + = (Element) original element. + \*/ + elproto.toggleClass = function (value, flag) { + if (flag != null) { + if (flag) { + return this.addClass(value); + } else { + return this.removeClass(value); + } + } + var classes = (value || "").match(rgNotSpace) || [], + elem = this.node, + className = elem.className.baseVal, + curClasses = className.match(rgNotSpace) || [], + j, + pos, + clazz, + finalValue; + j = 0; + while ((clazz = classes[j++])) { + pos = curClasses.indexOf(clazz); + if (~pos) { + curClasses.splice(pos, 1); + } else { + curClasses.push(clazz); + } + } + + finalValue = curClasses.join(" "); + if (className != finalValue) { + elem.className.baseVal = finalValue; + } + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var operators = { + "+": function (x, y) { + return x + y; + }, + "-": function (x, y) { + return x - y; + }, + "/": function (x, y) { + return x / y; + }, + "*": function (x, y) { + return x * y; + } + }, + Str = String, + reUnit = /[a-z]+$/i, + reAddon = /^\s*([+\-\/*])\s*=\s*([\d.eE+\-]+)\s*([^\d\s]+)?\s*$/; + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + eve.on("snap.util.attr", function (val) { + var plus = Str(val).match(reAddon); + if (plus) { + var evnt = eve.nt(), + name = evnt.substring(evnt.lastIndexOf(".") + 1), + a = this.attr(name), + atr = {}; + eve.stop(); + var unit = plus[3] || "", + aUnit = a.match(reUnit), + op = operators[plus[1]]; + if (aUnit && aUnit == unit) { + val = op(parseFloat(a), +plus[2]); + } else { + a = this.asPX(name); + val = op(this.asPX(name), this.asPX(name, plus[2] + unit)); + } + if (isNaN(a) || isNaN(val)) { + return; + } + atr[name] = val; + this.attr(atr); + } + })(-10); + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this, + bplus = Str(b).match(reAddon); + if (bplus) { + eve.stop(); + var unit = bplus[3] || "", + aUnit = a.match(reUnit), + op = operators[bplus[1]]; + if (aUnit && aUnit == unit) { + return { + from: parseFloat(a), + to: op(parseFloat(a), +bplus[2]), + f: getUnit(aUnit) + }; + } else { + a = this.asPX(name); + return { + from: a, + to: op(a, this.asPX(name, bplus[2] + unit)), + f: getNumber + }; + } + } + })(-10); +}); +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var proto = Paper.prototype, + is = Snap.is; + /*\ + * Paper.rect + [ method ] + * + * Draws a rectangle + ** + - x (number) x coordinate of the top left corner + - y (number) y coordinate of the top left corner + - width (number) width + - height (number) height + - rx (number) #optional horizontal radius for rounded corners, default is 0 + - ry (number) #optional vertical radius for rounded corners, default is rx or 0 + = (object) the `rect` element + ** + > Usage + | // regular rectangle + | var c = paper.rect(10, 10, 50, 50); + | // rectangle with rounded corners + | var c = paper.rect(40, 40, 50, 50, 10); + \*/ + proto.rect = function (x, y, w, h, rx, ry) { + var attr; + if (ry == null) { + ry = rx; + } + if (is(x, "object") && x == "[object Object]") { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + width: w, + height: h + }; + if (rx != null) { + attr.rx = rx; + attr.ry = ry; + } + } + return this.el("rect", attr); + }; + /*\ + * Paper.circle + [ method ] + ** + * Draws a circle + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - r (number) radius + = (object) the `circle` element + ** + > Usage + | var c = paper.circle(50, 50, 40); + \*/ + proto.circle = function (cx, cy, r) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr = { + cx: cx, + cy: cy, + r: r + }; + } + return this.el("circle", attr); + }; + + var preload = (function () { + function onerror() { + this.parentNode.removeChild(this); + } + return function (src, f) { + var img = glob.doc.createElement("img"), + body = glob.doc.body; + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(img); + img.onload = img.onerror = null; + body.removeChild(img); + }; + img.onerror = onerror; + body.appendChild(img); + img.src = src; + }; + }()); + + /*\ + * Paper.image + [ method ] + ** + * Places an image on the surface + ** + - src (string) URI of the source image + - x (number) x offset position + - y (number) y offset position + - width (number) width of the image + - height (number) height of the image + = (object) the `image` element + * or + = (object) Snap element object with type `image` + ** + > Usage + | var c = paper.image("apple.png", 10, 10, 80, 80); + \*/ + proto.image = function (src, x, y, width, height) { + var el = this.el("image"); + if (is(src, "object") && "src" in src) { + el.attr(src); + } else if (src != null) { + var set = { + "xlink:href": src, + preserveAspectRatio: "none" + }; + if (x != null && y != null) { + set.x = x; + set.y = y; + } + if (width != null && height != null) { + set.width = width; + set.height = height; + } else { + preload(src, function () { + Snap._.$(el.node, { + width: this.offsetWidth, + height: this.offsetHeight + }); + }); + } + Snap._.$(el.node, set); + } + return el; + }; + /*\ + * Paper.ellipse + [ method ] + ** + * Draws an ellipse + ** + - x (number) x coordinate of the centre + - y (number) y coordinate of the centre + - rx (number) horizontal radius + - ry (number) vertical radius + = (object) the `ellipse` element + ** + > Usage + | var c = paper.ellipse(50, 50, 40, 20); + \*/ + proto.ellipse = function (cx, cy, rx, ry) { + var attr; + if (is(cx, "object") && cx == "[object Object]") { + attr = cx; + } else if (cx != null) { + attr ={ + cx: cx, + cy: cy, + rx: rx, + ry: ry + }; + } + return this.el("ellipse", attr); + }; + // SIERRA Paper.path(): Unclear from the link what a Catmull-Rom curveto is, and why it would make life any easier. + /*\ + * Paper.path + [ method ] + ** + * Creates a `<path>` element using the given string as the path's definition + - pathString (string) #optional path string in SVG format + * Path string consists of one-letter commands, followed by comma seprarated arguments in numerical form. Example: + | "M10,20L30,40" + * This example features two commands: `M`, with arguments `(10, 20)` and `L` with arguments `(30, 40)`. Uppercase letter commands express coordinates in absolute terms, while lowercase commands express them in relative terms from the most recently declared coordinates. + * + # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a> or <a href="https://developer.mozilla.org/en/SVG/Tutorial/Paths">article about path strings at MDN</a>.</p> + # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> + # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> + # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> + # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> + # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> + # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> + # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> + # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> + # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> + # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> + # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> + # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> + * * _Catmull-Rom curveto_ is a not standard SVG command and added to make life easier. + * Note: there is a special case when a path consists of only three commands: `M10,10R…z`. In this case the path connects back to its starting point. + > Usage + | var c = paper.path("M10 10L90 90"); + | // draw a diagonal line: + | // move to 10,10, line to 90,90 + \*/ + proto.path = function (d) { + var attr; + if (is(d, "object") && !is(d, "array")) { + attr = d; + } else if (d) { + attr = {d: d}; + } + return this.el("path", attr); + }; + /*\ + * Paper.g + [ method ] + ** + * Creates a group element + ** + - varargs (…) #optional elements to nest within the group + = (object) the `g` element + ** + > Usage + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(c2, c1); // note that the order of elements is different + * or + | var c1 = paper.circle(), + | c2 = paper.rect(), + | g = paper.g(); + | g.add(c2, c1); + \*/ + /*\ + * Paper.group + [ method ] + ** + * See @Paper.g + \*/ + proto.group = proto.g = function (first) { + var attr, + el = this.el("g"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.svg + [ method ] + ** + * Creates a nested SVG element. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `svg` element + ** + \*/ + proto.svg = function (x, y, width, height, vbx, vby, vbw, vbh) { + var attrs = {}; + if (is(x, "object") && y == null) { + attrs = x; + } else { + if (x != null) { + attrs.x = x; + } + if (y != null) { + attrs.y = y; + } + if (width != null) { + attrs.width = width; + } + if (height != null) { + attrs.height = height; + } + if (vbx != null && vby != null && vbw != null && vbh != null) { + attrs.viewBox = [vbx, vby, vbw, vbh]; + } + } + return this.el("svg", attrs); + }; + /*\ + * Paper.mask + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a mask. + ** + = (object) the `mask` element + ** + \*/ + proto.mask = function (first) { + var attr, + el = this.el("mask"); + if (arguments.length == 1 && first && !first.type) { + el.attr(first); + } else if (arguments.length) { + el.add(Array.prototype.slice.call(arguments, 0)); + } + return el; + }; + /*\ + * Paper.ptrn + [ method ] + ** + * Equivalent in behaviour to @Paper.g, except it’s a pattern. + - x (number) @optional X of the element + - y (number) @optional Y of the element + - width (number) @optional width of the element + - height (number) @optional height of the element + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + ** + = (object) the `pattern` element + ** + \*/ + proto.ptrn = function (x, y, width, height, vx, vy, vw, vh) { + if (is(x, "object")) { + var attr = x; + } else { + attr = {patternUnits: "userSpaceOnUse"}; + if (x) { + attr.x = x; + } + if (y) { + attr.y = y; + } + if (width != null) { + attr.width = width; + } + if (height != null) { + attr.height = height; + } + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } else { + attr.viewBox = [x || 0, y || 0, width || 0, height || 0]; + } + } + return this.el("pattern", attr); + }; + /*\ + * Paper.use + [ method ] + ** + * Creates a <use> element. + - id (string) @optional id of element to link + * or + - id (Element) @optional element to link + ** + = (object) the `use` element + ** + \*/ + proto.use = function (id) { + if (id != null) { + if (id instanceof Element) { + if (!id.attr("id")) { + id.attr({id: Snap._.id(id)}); + } + id = id.attr("id"); + } + if (String(id).charAt() == "#") { + id = id.substring(1); + } + return this.el("use", {"xlink:href": "#" + id}); + } else { + return Element.prototype.use.call(this); + } + }; + /*\ + * Paper.symbol + [ method ] + ** + * Creates a <symbol> element. + - vbx (number) @optional viewbox X + - vby (number) @optional viewbox Y + - vbw (number) @optional viewbox width + - vbh (number) @optional viewbox height + = (object) the `symbol` element + ** + \*/ + proto.symbol = function (vx, vy, vw, vh) { + var attr = {}; + if (vx != null && vy != null && vw != null && vh != null) { + attr.viewBox = [vx, vy, vw, vh]; + } + + return this.el("symbol", attr); + }; + /*\ + * Paper.text + [ method ] + ** + * Draws a text string + ** + - x (number) x coordinate position + - y (number) y coordinate position + - text (string|array) The text string to draw or array of strings to nest within separate `<tspan>` elements + = (object) the `text` element + ** + > Usage + | var t1 = paper.text(50, 50, "Snap"); + | var t2 = paper.text(50, 50, ["S","n","a","p"]); + | // Text path usage + | t1.attr({textpath: "M10,10L100,100"}); + | // or + | var pth = paper.path("M10,10L100,100"); + | t1.attr({textpath: pth}); + \*/ + proto.text = function (x, y, text) { + var attr = {}; + if (is(x, "object")) { + attr = x; + } else if (x != null) { + attr = { + x: x, + y: y, + text: text || "" + }; + } + return this.el("text", attr); + }; + /*\ + * Paper.line + [ method ] + ** + * Draws a line + ** + - x1 (number) x coordinate position of the start + - y1 (number) y coordinate position of the start + - x2 (number) x coordinate position of the end + - y2 (number) y coordinate position of the end + = (object) the `line` element + ** + > Usage + | var t1 = paper.line(50, 50, 100, 100); + \*/ + proto.line = function (x1, y1, x2, y2) { + var attr = {}; + if (is(x1, "object")) { + attr = x1; + } else if (x1 != null) { + attr = { + x1: x1, + x2: x2, + y1: y1, + y2: y2 + }; + } + return this.el("line", attr); + }; + /*\ + * Paper.polyline + [ method ] + ** + * Draws a polyline + ** + - points (array) array of points + * or + - varargs (…) points + = (object) the `polyline` element + ** + > Usage + | var p1 = paper.polyline([10, 10, 100, 100]); + | var p2 = paper.polyline(10, 10, 100, 100); + \*/ + proto.polyline = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polyline", attr); + }; + /*\ + * Paper.polygon + [ method ] + ** + * Draws a polygon. See @Paper.polyline + \*/ + proto.polygon = function (points) { + if (arguments.length > 1) { + points = Array.prototype.slice.call(arguments, 0); + } + var attr = {}; + if (is(points, "object") && !is(points, "array")) { + attr = points; + } else if (points != null) { + attr = {points: points}; + } + return this.el("polygon", attr); + }; + // gradients + (function () { + var $ = Snap._.$; + // gradients' helpers + function Gstops() { + return this.selectAll("stop"); + } + function GaddStop(color, offset) { + var stop = $("stop"), + attr = { + offset: +offset + "%" + }; + color = Snap.color(color); + attr["stop-color"] = color.hex; + if (color.opacity < 1) { + attr["stop-opacity"] = color.opacity; + } + $(stop, attr); + this.node.appendChild(stop); + return this; + } + function GgetBBox() { + if (this.type == "linearGradient") { + var x1 = $(this.node, "x1") || 0, + x2 = $(this.node, "x2") || 1, + y1 = $(this.node, "y1") || 0, + y2 = $(this.node, "y2") || 0; + return Snap._.box(x1, y1, math.abs(x2 - x1), math.abs(y2 - y1)); + } else { + var cx = this.node.cx || .5, + cy = this.node.cy || .5, + r = this.node.r || 0; + return Snap._.box(cx - r, cy - r, r * 2, r * 2); + } + } + function gradient(defs, str) { + var grad = eve("snap.util.grad.parse", null, str).firstDefined(), + el; + if (!grad) { + return null; + } + grad.params.unshift(defs); + if (grad.type.toLowerCase() == "l") { + el = gradientLinear.apply(0, grad.params); + } else { + el = gradientRadial.apply(0, grad.params); + } + if (grad.type != grad.type.toLowerCase()) { + $(el.node, { + gradientUnits: "userSpaceOnUse" + }); + } + var stops = grad.stops, + len = stops.length, + start = 0, + j = 0; + function seed(i, end) { + var step = (end - start) / (i - j); + for (var k = j; k < i; k++) { + stops[k].offset = +(+start + step * (k - j)).toFixed(2); + } + j = i; + start = end; + } + len--; + for (var i = 0; i < len; i++) if ("offset" in stops[i]) { + seed(i, stops[i].offset); + } + stops[len].offset = stops[len].offset || 100; + seed(len, stops[len].offset); + for (i = 0; i <= len; i++) { + var stop = stops[i]; + el.addStop(stop.color, stop.offset); + } + return el; + } + function gradientLinear(defs, x1, y1, x2, y2) { + var el = Snap._.make("linearGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (x1 != null) { + $(el.node, { + x1: x1, + y1: y1, + x2: x2, + y2: y2 + }); + } + return el; + } + function gradientRadial(defs, cx, cy, r, fx, fy) { + var el = Snap._.make("radialGradient", defs); + el.stops = Gstops; + el.addStop = GaddStop; + el.getBBox = GgetBBox; + if (cx != null) { + $(el.node, { + cx: cx, + cy: cy, + r: r + }); + } + if (fx != null && fy != null) { + $(el.node, { + fx: fx, + fy: fy + }); + } + return el; + } + /*\ + * Paper.gradient + [ method ] + ** + * Creates a gradient element + ** + - gradient (string) gradient descriptor + > Gradient Descriptor + * The gradient descriptor is an expression formatted as + * follows: `<type>(<coords>)<colors>`. The `<type>` can be + * either linear or radial. The uppercase `L` or `R` letters + * indicate absolute coordinates offset from the SVG surface. + * Lowercase `l` or `r` letters indicate coordinates + * calculated relative to the element to which the gradient is + * applied. Coordinates specify a linear gradient vector as + * `x1`, `y1`, `x2`, `y2`, or a radial gradient as `cx`, `cy`, + * `r` and optional `fx`, `fy` specifying a focal point away + * from the center of the circle. Specify `<colors>` as a list + * of dash-separated CSS color values. Each color may be + * followed by a custom offset value, separated with a colon + * character. + > Examples + * Linear gradient, relative from top-left corner to bottom-right + * corner, from black through red to white: + | var g = paper.gradient("l(0, 0, 1, 1)#000-#f00-#fff"); + * Linear gradient, absolute from (0, 0) to (100, 100), from black + * through red at 25% to white: + | var g = paper.gradient("L(0, 0, 100, 100)#000-#f00:25-#fff"); + * Radial gradient, relative from the center of the element with radius + * half the width, from black to white: + | var g = paper.gradient("r(0.5, 0.5, 0.5)#000-#fff"); + * To apply the gradient: + | paper.circle(50, 50, 40).attr({ + | fill: g + | }); + = (object) the `gradient` element + \*/ + proto.gradient = function (str) { + return gradient(this.defs, str); + }; + proto.gradientLinear = function (x1, y1, x2, y2) { + return gradientLinear(this.defs, x1, y1, x2, y2); + }; + proto.gradientRadial = function (cx, cy, r, fx, fy) { + return gradientRadial(this.defs, cx, cy, r, fx, fy); + }; + /*\ + * Paper.toString + [ method ] + ** + * Returns SVG code for the @Paper + = (string) SVG code for the @Paper + \*/ + proto.toString = function () { + var doc = this.node.ownerDocument, + f = doc.createDocumentFragment(), + d = doc.createElement("div"), + svg = this.node.cloneNode(true), + res; + f.appendChild(d); + d.appendChild(svg); + Snap._.$(svg, {xmlns: "http://www.w3.org/2000/svg"}); + res = d.innerHTML; + f.removeChild(f.firstChild); + return res; + }; + /*\ + * Paper.toDataURL + [ method ] + ** + * Returns SVG code for the @Paper as Data URI string. + = (string) Data URI string + \*/ + proto.toDataURL = function () { + if (window && window.btoa) { + return "data:image/svg+xml;base64," + btoa(unescape(encodeURIComponent(this))); + } + }; + /*\ + * Paper.clear + [ method ] + ** + * Removes all child nodes of the paper, except <defs>. + \*/ + proto.clear = function () { + var node = this.node.firstChild, + next; + while (node) { + next = node.nextSibling; + if (node.tagName != "defs") { + node.parentNode.removeChild(node); + } else { + proto.clear.call({node: node}); + } + node = next; + } + }; + }()); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + is = Snap.is, + clone = Snap._.clone, + has = "hasOwnProperty", + p2s = /,?([a-z]),?/gi, + toFloat = parseFloat, + math = Math, + PI = math.PI, + mmin = math.min, + mmax = math.max, + pow = math.pow, + abs = math.abs; + function paths(ps) { + var p = paths.ps = paths.ps || {}; + if (p[ps]) { + p[ps].sleep = 100; + } else { + p[ps] = { + sleep: 100 + }; + } + setTimeout(function () { + for (var key in p) if (p[has](key) && key != ps) { + p[key].sleep--; + !p[key].sleep && delete p[key]; + } + }); + return p[ps]; + } + function box(x, y, width, height) { + if (x == null) { + x = y = width = height = 0; + } + if (y == null) { + y = x.y; + width = x.width; + height = x.height; + x = x.x; + } + return { + x: x, + y: y, + width: width, + w: width, + height: height, + h: height, + x2: x + width, + y2: y + height, + cx: x + width / 2, + cy: y + height / 2, + r1: math.min(width, height) / 2, + r2: math.max(width, height) / 2, + r0: math.sqrt(width * width + height * height) / 2, + path: rectPath(x, y, width, height), + vb: [x, y, width, height].join(" ") + }; + } + function toString() { + return this.join(",").replace(p2s, "$1"); + } + function pathClone(pathArray) { + var res = clone(pathArray); + res.toString = toString; + return res; + } + function getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + if (length == null) { + return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + } else { + return findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, + getTotLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); + } + } + function getLengthFactory(istotal, subpath) { + function O(val) { + return +(+val).toFixed(3); + } + return Snap._.cacher(function (path, length, onlystart) { + if (path instanceof Element) { + path = path.attr("d"); + } + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += [ + "C" + O(point.start.x), + O(point.start.y), + O(point.m.x), + O(point.m.y), + O(point.x), + O(point.y) + ]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = [ + "M" + O(point.x), + O(point.y) + "C" + O(point.n.x), + O(point.n.y), + O(point.end.x), + O(point.end.y), + O(p[5]), + O(p[6]) + ].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return point; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + return point; + }, null, Snap._.clone); + } + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + function findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + // (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + } + function bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + if (!Snap.is(p1x, "array")) { + p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; + } + var bbox = curveDim.apply(null, p1x); + return box( + bbox.min.x, + bbox.min.y, + bbox.max.x - bbox.min.x, + bbox.max.y - bbox.min.y + ); + } + function isPointInsideBBox(bbox, x, y) { + return x >= bbox.x && + x <= bbox.x + bbox.width && + y >= bbox.y && + y <= bbox.y + bbox.height; + } + function isBBoxIntersect(bbox1, bbox2) { + bbox1 = box(bbox1); + bbox2 = box(bbox2); + return isPointInsideBBox(bbox2, bbox1.x, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y) + || isPointInsideBBox(bbox2, bbox1.x, bbox1.y2) + || isPointInsideBBox(bbox2, bbox1.x2, bbox1.y2) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y) + || isPointInsideBBox(bbox1, bbox2.x, bbox2.y2) + || isPointInsideBBox(bbox1, bbox2.x2, bbox2.y2) + || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x + || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) + && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y + || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); + } + function base3(t, p1, p2, p3, p4) { + var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, + t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; + return t * t2 - 3 * p1 + 3 * p2; + } + function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { + if (z == null) { + z = 1; + } + z = z > 1 ? 1 : z < 0 ? 0 : z; + var z2 = z / 2, + n = 12, + Tvalues = [-.1252,.1252,-.3678,.3678,-.5873,.5873,-.7699,.7699,-.9041,.9041,-.9816,.9816], + Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], + sum = 0; + for (var i = 0; i < n; i++) { + var ct = z2 * Tvalues[i] + z2, + xbase = base3(ct, x1, x2, x3, x4), + ybase = base3(ct, y1, y2, y3, y4), + comb = xbase * xbase + ybase * ybase; + sum += Cvalues[i] * math.sqrt(comb); + } + return z2 * sum; + } + function getTotLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { + if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { + return; + } + var t = 1, + step = t / 2, + t2 = t - step, + l, + e = .01; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + while (abs(l - ll) > e) { + step /= 2; + t2 += (l < ll ? 1 : -1) * step; + l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); + } + return t2; + } + function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { + if ( + mmax(x1, x2) < mmin(x3, x4) || + mmin(x1, x2) > mmax(x3, x4) || + mmax(y1, y2) < mmin(y3, y4) || + mmin(y1, y2) > mmax(y3, y4) + ) { + return; + } + var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), + ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), + denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); + + if (!denominator) { + return; + } + var px = nx / denominator, + py = ny / denominator, + px2 = +px.toFixed(2), + py2 = +py.toFixed(2); + if ( + px2 < +mmin(x1, x2).toFixed(2) || + px2 > +mmax(x1, x2).toFixed(2) || + px2 < +mmin(x3, x4).toFixed(2) || + px2 > +mmax(x3, x4).toFixed(2) || + py2 < +mmin(y1, y2).toFixed(2) || + py2 > +mmax(y1, y2).toFixed(2) || + py2 < +mmin(y3, y4).toFixed(2) || + py2 > +mmax(y3, y4).toFixed(2) + ) { + return; + } + return {x: px, y: py}; + } + function inter(bez1, bez2) { + return interHelper(bez1, bez2); + } + function interCount(bez1, bez2) { + return interHelper(bez1, bez2, 1); + } + function interHelper(bez1, bez2, justCount) { + var bbox1 = bezierBBox(bez1), + bbox2 = bezierBBox(bez2); + if (!isBBoxIntersect(bbox1, bbox2)) { + return justCount ? 0 : []; + } + var l1 = bezlen.apply(0, bez1), + l2 = bezlen.apply(0, bez2), + n1 = ~~(l1 / 8), + n2 = ~~(l2 / 8), + dots1 = [], + dots2 = [], + xy = {}, + res = justCount ? 0 : []; + for (var i = 0; i < n1 + 1; i++) { + var p = findDotsAtSegment.apply(0, bez1.concat(i / n1)); + dots1.push({x: p.x, y: p.y, t: i / n1}); + } + for (i = 0; i < n2 + 1; i++) { + p = findDotsAtSegment.apply(0, bez2.concat(i / n2)); + dots2.push({x: p.x, y: p.y, t: i / n2}); + } + for (i = 0; i < n1; i++) { + for (var j = 0; j < n2; j++) { + var di = dots1[i], + di1 = dots1[i + 1], + dj = dots2[j], + dj1 = dots2[j + 1], + ci = abs(di1.x - di.x) < .001 ? "y" : "x", + cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", + is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); + if (is) { + if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { + continue; + } + xy[is.x.toFixed(4)] = is.y.toFixed(4); + var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), + t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); + if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) { + if (justCount) { + res++; + } else { + res.push({ + x: is.x, + y: is.y, + t1: t1, + t2: t2 + }); + } + } + } + } + } + return res; + } + function pathIntersection(path1, path2) { + return interPathHelper(path1, path2); + } + function pathIntersectionNumber(path1, path2) { + return interPathHelper(path1, path2, 1); + } + function interPathHelper(path1, path2, justCount) { + path1 = path2curve(path1); + path2 = path2curve(path2); + var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, + res = justCount ? 0 : []; + for (var i = 0, ii = path1.length; i < ii; i++) { + var pi = path1[i]; + if (pi[0] == "M") { + x1 = x1m = pi[1]; + y1 = y1m = pi[2]; + } else { + if (pi[0] == "C") { + bez1 = [x1, y1].concat(pi.slice(1)); + x1 = bez1[6]; + y1 = bez1[7]; + } else { + bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; + x1 = x1m; + y1 = y1m; + } + for (var j = 0, jj = path2.length; j < jj; j++) { + var pj = path2[j]; + if (pj[0] == "M") { + x2 = x2m = pj[1]; + y2 = y2m = pj[2]; + } else { + if (pj[0] == "C") { + bez2 = [x2, y2].concat(pj.slice(1)); + x2 = bez2[6]; + y2 = bez2[7]; + } else { + bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; + x2 = x2m; + y2 = y2m; + } + var intr = interHelper(bez1, bez2, justCount); + if (justCount) { + res += intr; + } else { + for (var k = 0, kk = intr.length; k < kk; k++) { + intr[k].segment1 = i; + intr[k].segment2 = j; + intr[k].bez1 = bez1; + intr[k].bez2 = bez2; + } + res = res.concat(intr); + } + } + } + } + } + return res; + } + function isPointInsidePath(path, x, y) { + var bbox = pathBBox(path); + return isPointInsideBBox(bbox, x, y) && + interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; + } + function pathBBox(path) { + var pth = paths(path); + if (pth.bbox) { + return clone(pth.bbox); + } + if (!path) { + return box(); + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X.concat(dim.min.x, dim.max.x); + Y = Y.concat(dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin.apply(0, X), + ymin = mmin.apply(0, Y), + xmax = mmax.apply(0, X), + ymax = mmax.apply(0, Y), + bb = box(xmin, ymin, xmax - xmin, ymax - ymin); + pth.bbox = clone(bb); + return bb; + } + function rectPath(x, y, w, h, r) { + if (r) { + return [ + ["M", +x + (+r), y], + ["l", w - r * 2, 0], + ["a", r, r, 0, 0, 1, r, r], + ["l", 0, h - r * 2], + ["a", r, r, 0, 0, 1, -r, r], + ["l", r * 2 - w, 0], + ["a", r, r, 0, 0, 1, -r, -r], + ["l", 0, r * 2 - h], + ["a", r, r, 0, 0, 1, r, -r], + ["z"] + ]; + } + var res = [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + res.toString = toString; + return res; + } + function ellipsePath(x, y, rx, ry, a) { + if (a == null && ry == null) { + ry = rx; + } + x = +x; + y = +y; + rx = +rx; + ry = +ry; + if (a != null) { + var rad = Math.PI / 180, + x1 = x + rx * Math.cos(-ry * rad), + x2 = x + rx * Math.cos(-a * rad), + y1 = y + rx * Math.sin(-ry * rad), + y2 = y + rx * Math.sin(-a * rad), + res = [["M", x1, y1], ["A", rx, rx, 0, +(a - ry > 180), 0, x2, y2]]; + } else { + res = [ + ["M", x, y], + ["m", 0, -ry], + ["a", rx, ry, 0, 1, 1, 0, 2 * ry], + ["a", rx, ry, 0, 1, 1, 0, -2 * ry], + ["z"] + ]; + } + res.toString = toString; + return res; + } + var unit2px = Snap._unit2px, + getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx, attr.cy, attr.r); + }, + ellipse: function (el) { + var attr = unit2px(el); + return ellipsePath(attr.cx || 0, attr.cy || 0, attr.rx, attr.ry); + }, + rect: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height, attr.rx, attr.ry); + }, + image: function (el) { + var attr = unit2px(el); + return rectPath(attr.x || 0, attr.y || 0, attr.width, attr.height); + }, + line: function (el) { + return "M" + [el.attr("x1") || 0, el.attr("y1") || 0, el.attr("x2"), el.attr("y2")]; + }, + polyline: function (el) { + return "M" + el.attr("points"); + }, + polygon: function (el) { + return "M" + el.attr("points") + "z"; + }, + deflt: function (el) { + var bbox = el.node.getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }; + function pathToRelative(pathArray) { + var pth = paths(pathArray), + lowerCase = String.prototype.toLowerCase; + if (pth.rel) { + return pathClone(pth.rel); + } + if (!Snap.is(pathArray, "array") || !Snap.is(pathArray && pathArray[0], "array")) { + pathArray = Snap.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = toString; + pth.rel = pathClone(res); + return res; + } + function pathToAbsolute(pathArray) { + var pth = paths(pathArray); + if (pth.abs) { + return pathClone(pth.abs); + } + if (!is(pathArray, "array") || !is(pathArray && pathArray[0], "array")) { // rough assumption + pathArray = Snap.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0, + pa0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + var crz = pathArray.length == 3 && + pathArray[0][0] == "M" && + pathArray[1][0].toUpperCase() == "R" && + pathArray[2][0].toUpperCase() == "Z"; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + pa0 = pa[0]; + if (pa0 != pa0.toUpperCase()) { + r[0] = pa0.toUpperCase(); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +pa[6] + x; + r[7] = +pa[7] + y; + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y].concat(pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + break; + case "O": + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + break; + case "U": + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa0 == "R") { + dots = [x, y].concat(pa.slice(1)); + res.pop(); + res = res.concat(catmullRom2bezier(dots, crz)); + r = ["R"].concat(pa.slice(-2)); + } else if (pa0 == "O") { + res.pop(); + dots = ellipsePath(x, y, pa[1], pa[2]); + dots.push(dots[0]); + res = res.concat(dots); + } else if (pa0 == "U") { + res.pop(); + res = res.concat(ellipsePath(x, y, pa[1], pa[2], pa[3])); + r = ["U"].concat(res[res.length - 1].slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + pa0 = pa0.toUpperCase(); + if (pa0 != "O") { + switch (r[0]) { + case "Z": + x = +mx; + y = +my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + } + res.toString = toString; + pth.abs = pathClone(res); + return res; + } + function l2c(x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + } + function q2c(x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + } + function a2c(x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = Snap._.cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4].concat(res); + } else { + res = [m2, m3, m4].concat(res).join().split(","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + } + function findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + } + + // Returns bounding box of cubic bezier curve. + // Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + // Original version: NISHIO Hirokazu + // Modifications: https://github.com/timo22345 + function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) { + var tvalues = [], + bounds = [[], []], + a, b, c, t, t1, t2, b2ac, sqrtb2ac; + for (var i = 0; i < 2; ++i) { + if (i == 0) { + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + } else { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + if (abs(a) < 1e-12) { + if (abs(b) < 1e-12) { + continue; + } + t = -c / b; + if (0 < t && t < 1) { + tvalues.push(t); + } + continue; + } + b2ac = b * b - 4 * c * a; + sqrtb2ac = math.sqrt(b2ac); + if (b2ac < 0) { + continue; + } + t1 = (-b + sqrtb2ac) / (2 * a); + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + t2 = (-b - sqrtb2ac) / (2 * a); + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + var x, y, j = tvalues.length, + jlen = j, + mt; + while (j--) { + t = tvalues[j]; + mt = 1 - t; + bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); + bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + bounds[0].length = bounds[1].length = jlen + 2; + + + return { + min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])}, + max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])} + }; + } + + function path2curve(path, path2) { + var pth = !path2 && paths(path); + if (!path2 && pth.curve) { + return pathClone(pth.curve); + } + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d, pcom) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1)))); + break; + case "S": + if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. + nx = d.x * 2 - d.bx; // And reflect the previous + ny = d.y * 2 - d.by; // command's control point relative to the current point. + } + else { // or some else or nothing + nx = d.x; + ny = d.y; + } + path = ["C", nx, ny].concat(path.slice(1)); + break; + case "T": + if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. + d.qx = d.x * 2 - d.qx; // And make a reflection similar + d.qy = d.y * 2 - d.qy; // to case "S". + } + else { // or something else or nothing + d.qx = d.x; + d.qy = d.y; + } + path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"].concat(q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"].concat(l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"].concat(l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"].concat(l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"].concat(l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved + p2 && (pcoms2[i] = "A"); // the same as above + pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + pcoms1 = [], // path commands of original path p + pcoms2 = [], // path commands of original path p2 + pfirst = "", // temporary holder for original path command + pcom = ""; // holder for previous path command of original path + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] && (pfirst = p[i][0]); // save current path command + + if (pfirst != "C") // C is not saved yet, because it may be result of conversion + { + pcoms1[i] = pfirst; // Save current path command + i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom + } + p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath + + if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command + // which may produce multiple C:s + // so we have to make sure that C is also C in original path + + fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 + + if (p2) { // the same procedures is done to p2 + p2[i] && (pfirst = p2[i][0]); + if (pfirst != "C") { + pcoms2[i] = pfirst; + i && (pcom = pcoms2[i - 1]); + } + p2[i] = processPath(p2[i], attrs2, pcom); + + if (pcoms2[i] != "A" && pfirst == "C") { + pcoms2[i] = "C"; + } + + fixArc(p2, i); + } + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + if (!p2) { + pth.curve = pathClone(p); + } + return p2 ? [p, p2] : p; + } + function mapPath(path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + } + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp, z) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { + var p = [ + {x: +crp[i - 2], y: +crp[i - 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]} + ]; + if (z) { + if (!i) { + p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; + } else if (iLen - 4 == i) { + p[3] = {x: +crp[0], y: +crp[1]}; + } else if (iLen - 2 == i) { + p[2] = {x: +crp[0], y: +crp[1]}; + p[3] = {x: +crp[2], y: +crp[3]}; + } + } else { + if (iLen - 4 == i) { + p[3] = p[2]; + } else if (!i) { + p[0] = {x: +crp[i], y: +crp[i + 1]}; + } + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + // export + Snap.path = paths; + + /*\ + * Snap.path.getTotalLength + [ method ] + ** + * Returns the length of the given path in pixels + ** + - path (string) SVG path string + ** + = (number) length + \*/ + Snap.path.getTotalLength = getTotalLength; + /*\ + * Snap.path.getPointAtLength + [ method ] + ** + * Returns the coordinates of the point located at the given length along the given path + ** + - path (string) SVG path string + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + Snap.path.getPointAtLength = getPointAtLength; + /*\ + * Snap.path.getSubpath + [ method ] + ** + * Returns the subpath of a given path between given start and end lengths + ** + - path (string) SVG path string + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + Snap.path.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + /*\ + * Element.getTotalLength + [ method ] + ** + * Returns the length of the path in pixels (only works for `path` elements) + = (number) length + \*/ + elproto.getTotalLength = function () { + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + }; + // SIERRA Element.getPointAtLength()/Element.getTotalLength(): If a <path> is broken into different segments, is the jump distance to the new coordinates set by the _M_ or _m_ commands calculated as part of the path's total length? + /*\ + * Element.getPointAtLength + [ method ] + ** + * Returns coordinates of the point located at the given length on the given path (only works for `path` elements) + ** + - length (number) length, in pixels, from the start of the path, excluding non-rendering jumps + ** + = (object) representation of the point: + o { + o x: (number) x coordinate, + o y: (number) y coordinate, + o alpha: (number) angle of derivative + o } + \*/ + elproto.getPointAtLength = function (length) { + return getPointAtLength(this.attr("d"), length); + }; + // SIERRA Element.getSubpath(): Similar to the problem for Element.getPointAtLength(). Unclear how this would work for a segmented path. Overall, the concept of _subpath_ and what I'm calling a _segment_ (series of non-_M_ or _Z_ commands) is unclear. + /*\ + * Element.getSubpath + [ method ] + ** + * Returns subpath of a given element from given start and end lengths (only works for `path` elements) + ** + - from (number) length, in pixels, from the start of the path to the start of the segment + - to (number) length, in pixels, from the start of the path to the end of the segment + ** + = (string) path string definition for the segment + \*/ + elproto.getSubpath = function (from, to) { + return Snap.path.getSubpath(this.attr("d"), from, to); + }; + Snap._.box = box; + /*\ + * Snap.path.findDotsAtSegment + [ method ] + ** + * Utility method + ** + * Finds dot coordinates on the given cubic beziér curve at the given t + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + - t (number) position on the curve (0..1) + = (object) point information in format: + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o m: { + o x: (number) x coordinate of the left anchor, + o y: (number) y coordinate of the left anchor + o }, + o n: { + o x: (number) x coordinate of the right anchor, + o y: (number) y coordinate of the right anchor + o }, + o start: { + o x: (number) x coordinate of the start of the curve, + o y: (number) y coordinate of the start of the curve + o }, + o end: { + o x: (number) x coordinate of the end of the curve, + o y: (number) y coordinate of the end of the curve + o }, + o alpha: (number) angle of the curve derivative at the point + o } + \*/ + Snap.path.findDotsAtSegment = findDotsAtSegment; + /*\ + * Snap.path.bezierBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given cubic beziér curve + - p1x (number) x of the first point of the curve + - p1y (number) y of the first point of the curve + - c1x (number) x of the first anchor of the curve + - c1y (number) y of the first anchor of the curve + - c2x (number) x of the second anchor of the curve + - c2y (number) y of the second anchor of the curve + - p2x (number) x of the second point of the curve + - p2y (number) y of the second point of the curve + * or + - bez (array) array of six points for beziér curve + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.bezierBBox = bezierBBox; + /*\ + * Snap.path.isPointInsideBBox + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside bounding box + - bbox (string) bounding box + - x (string) x coordinate of the point + - y (string) y coordinate of the point + = (boolean) `true` if point is inside + \*/ + Snap.path.isPointInsideBBox = isPointInsideBBox; + Snap.closest = function (x, y, X, Y) { + var r = 100, + b = box(x - r / 2, y - r / 2, r, r), + inside = [], + getter = X[0].hasOwnProperty("x") ? function (i) { + return { + x: X[i].x, + y: X[i].y + }; + } : function (i) { + return { + x: X[i], + y: Y[i] + }; + }, + found = 0; + while (r <= 1e6 && !found) { + for (var i = 0, ii = X.length; i < ii; i++) { + var xy = getter(i); + if (isPointInsideBBox(b, xy.x, xy.y)) { + found++; + inside.push(xy); + break; + } + } + if (!found) { + r *= 2; + b = box(x - r / 2, y - r / 2, r, r) + } + } + if (r == 1e6) { + return; + } + var len = Infinity, + res; + for (i = 0, ii = inside.length; i < ii; i++) { + var l = Snap.len(x, y, inside[i].x, inside[i].y); + if (len > l) { + len = l; + inside[i].len = l; + res = inside[i]; + } + } + return res; + }; + /*\ + * Snap.path.isBBoxIntersect + [ method ] + ** + * Utility method + ** + * Returns `true` if two bounding boxes intersect + - bbox1 (string) first bounding box + - bbox2 (string) second bounding box + = (boolean) `true` if bounding boxes intersect + \*/ + Snap.path.isBBoxIntersect = isBBoxIntersect; + /*\ + * Snap.path.intersection + [ method ] + ** + * Utility method + ** + * Finds intersections of two paths + - path1 (string) path string + - path2 (string) path string + = (array) dots of intersection + o [ + o { + o x: (number) x coordinate of the point, + o y: (number) y coordinate of the point, + o t1: (number) t value for segment of path1, + o t2: (number) t value for segment of path2, + o segment1: (number) order number for segment of path1, + o segment2: (number) order number for segment of path2, + o bez1: (array) eight coordinates representing beziér curve for the segment of path1, + o bez2: (array) eight coordinates representing beziér curve for the segment of path2 + o } + o ] + \*/ + Snap.path.intersection = pathIntersection; + Snap.path.intersectionNumber = pathIntersectionNumber; + /*\ + * Snap.path.isPointInside + [ method ] + ** + * Utility method + ** + * Returns `true` if given point is inside a given closed path. + * + * Note: fill mode doesn’t affect the result of this method. + - path (string) path string + - x (number) x of the point + - y (number) y of the point + = (boolean) `true` if point is inside the path + \*/ + Snap.path.isPointInside = isPointInsidePath; + /*\ + * Snap.path.getBBox + [ method ] + ** + * Utility method + ** + * Returns the bounding box of a given path + - path (string) path string + = (object) bounding box + o { + o x: (number) x coordinate of the left top point of the box, + o y: (number) y coordinate of the left top point of the box, + o x2: (number) x coordinate of the right bottom point of the box, + o y2: (number) y coordinate of the right bottom point of the box, + o width: (number) width of the box, + o height: (number) height of the box + o } + \*/ + Snap.path.getBBox = pathBBox; + Snap.path.get = getPath; + /*\ + * Snap.path.toRelative + [ method ] + ** + * Utility method + ** + * Converts path coordinates into relative values + - path (string) path string + = (array) path string + \*/ + Snap.path.toRelative = pathToRelative; + /*\ + * Snap.path.toAbsolute + [ method ] + ** + * Utility method + ** + * Converts path coordinates into absolute values + - path (string) path string + = (array) path string + \*/ + Snap.path.toAbsolute = pathToAbsolute; + /*\ + * Snap.path.toCubic + [ method ] + ** + * Utility method + ** + * Converts path to a new path where all segments are cubic beziér curves + - pathString (string|array) path string or array of segments + = (array) array of segments + \*/ + Snap.path.toCubic = path2curve; + /*\ + * Snap.path.map + [ method ] + ** + * Transform the path string with the given matrix + - path (string) path string + - matrix (object) see @Matrix + = (string) transformed path string + \*/ + Snap.path.map = mapPath; + Snap.path.toString = toString; + Snap.path.clone = pathClone; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var mmax = Math.max, + mmin = Math.min; + + // Set + var Set = function (items) { + this.items = []; + this.bindings = {}; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i]) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + /*\ + * Set.push + [ method ] + ** + * Adds each argument to the current set + = (object) original element + \*/ + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + /*\ + * Set.pop + [ method ] + ** + * Removes last element and returns it + = (object) element + \*/ + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + /*\ + * Set.forEach + [ method ] + ** + * Executes given function for each element in the set + * + * If the function returns `false`, the loop stops running. + ** + - callback (function) function to run + - thisArg (object) context object for the callback + = (object) Set object + \*/ + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + /*\ + * Set.animate + [ method ] + ** + * Animates each element in set in sync. + * + ** + - attrs (object) key-value pairs of destination attributes + - duration (number) duration of the animation in milliseconds + - easing (function) #optional easing function from @mina or custom + - callback (function) #optional callback function that executes when the animation ends + * or + - animation (array) array of animation parameter for each element in set in format `[attrs, duration, easing, callback]` + > Usage + | // animate all elements in set to radius 10 + | set.animate({r: 10}, 500, mina.easein); + | // or + | // animate first element to radius 10, but second to radius 20 and in different time + | set.animate([{r: 10}, 500, mina.easein], [{r: 20}, 1500, mina.easein]); + = (Element) the current element + \*/ + setproto.animate = function (attrs, ms, easing, callback) { + if (typeof easing == "function" && !easing.length) { + callback = easing; + easing = mina.linear; + } + if (attrs instanceof Snap._.Animation) { + callback = attrs.callback; + easing = attrs.easing; + ms = easing.dur; + attrs = attrs.attr; + } + var args = arguments; + if (Snap.is(attrs, "array") && Snap.is(args[args.length - 1], "array")) { + var each = true; + } + var begin, + handler = function () { + if (begin) { + this.b = begin; + } else { + begin = this.b; + } + }, + cb = 0, + set = this, + callbacker = callback && function () { + if (++cb == set.length) { + callback.call(this); + } + }; + return this.forEach(function (el, i) { + eve.once("snap.animcreated." + el.id, handler); + if (each) { + args[i] && el.animate.apply(el, args[i]); + } else { + el.animate(attrs, ms, easing, callbacker); + } + }); + }; + setproto.remove = function () { + while (this.length) { + this.pop().remove(); + } + return this; + }; + /*\ + * Set.bind + [ method ] + ** + * Specifies how to handle a specific attribute when applied + * to a set. + * + ** + - attr (string) attribute name + - callback (function) function to run + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + * or + - attr (string) attribute name + - element (Element) specific element in the set to apply the attribute to + - eattr (string) attribute on the element to bind the attribute to + = (object) Set object + \*/ + setproto.bind = function (attr, a, b) { + var data = {}; + if (typeof a == "function") { + this.bindings[attr] = a; + } else { + var aname = b || attr; + this.bindings[attr] = function (v) { + data[aname] = v; + a.attr(data); + }; + } + return this; + }; + setproto.attr = function (value) { + var unbound = {}; + for (var k in value) { + if (this.bindings[k]) { + this.bindings[k](value[k]); + } else { + unbound[k] = value[k]; + } + } + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(unbound); + } + return this; + }; + /*\ + * Set.clear + [ method ] + ** + * Removes all elements from the set + \*/ + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + /*\ + * Set.splice + [ method ] + ** + * Removes range of elements from the set + ** + - index (number) position of the deletion + - count (number) number of element to remove + - insertion… (object) #optional elements to insert + = (object) set elements that were deleted + \*/ + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + /*\ + * Set.exclude + [ method ] + ** + * Removes given element from the set + ** + - element (object) element to remove + = (boolean) `true` if object was found and removed from the set + \*/ + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + return false; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + x2 = [], + y2 = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + x2.push(box.x + box.width); + y2.push(box.y + box.height); + } + x = mmin.apply(0, x); + y = mmin.apply(0, y); + x2 = mmax.apply(0, x2); + y2 = mmax.apply(0, y2); + return { + x: x, + y: y, + x2: x2, + y2: y2, + width: x2 - x, + height: y2 - y, + cx: x + (x2 - x) / 2, + cy: y + (y2 - y) / 2 + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Snap\u2018s set"; + }; + setproto.type = "set"; + // export + Snap.Set = Set; + Snap.set = function () { + var set = new Set; + if (arguments.length) { + set.push.apply(set, Array.prototype.slice.call(arguments, 0)); + } + return set; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var names = {}, + reUnit = /[a-z]+$/i, + Str = String; + names.stroke = names.fill = "colour"; + function getEmpty(item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + } + function equaliseTransform(t1, t2, getBBox) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = Snap.parseTransformString(t1) || []; + t2 = Snap.parseTransformString(t2) || []; + var maxlength = Math.max(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + t1 = Snap._.transform2matrix(t1, getBBox()); + t2 = Snap._.transform2matrix(t2, getBBox()); + from = [["m", t1.a, t1.b, t1.c, t1.d, t1.e, t1.f]]; + to = [["m", t2.a, t2.b, t2.c, t2.d, t2.e, t2.f]]; + break; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = Math.max(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: path2array(from), + to: path2array(to), + f: getPath(from) + }; + } + function getNumber(val) { + return val; + } + function getUnit(unit) { + return function (val) { + return +val.toFixed(3) + unit; + }; + } + function getViewBox(val) { + return val.join(" "); + } + function getColour(clr) { + return Snap.rgb(clr[0], clr[1], clr[2]); + } + function getPath(path) { + var k = 0, i, ii, j, jj, out, a, b = []; + for (i = 0, ii = path.length; i < ii; i++) { + out = "["; + a = ['"' + path[i][0] + '"']; + for (j = 1, jj = path[i].length; j < jj; j++) { + a[j] = "val[" + (k++) + "]"; + } + out += a + "]"; + b[i] = out; + } + return Function("val", "return Snap.path.toString.call([" + b + "])"); + } + function path2array(path) { + var out = []; + for (var i = 0, ii = path.length; i < ii; i++) { + for (var j = 1, jj = path[i].length; j < jj; j++) { + out.push(path[i][j]); + } + } + return out; + } + function isNumeric(obj) { + return isFinite(parseFloat(obj)); + } + function arrayEqual(arr1, arr2) { + if (!Snap.is(arr1, "array") || !Snap.is(arr2, "array")) { + return false; + } + return arr1.toString() == arr2.toString(); + } + Element.prototype.equal = function (name, b) { + return eve("snap.util.equal", this, name, b).firstDefined(); + }; + eve.on("snap.util.equal", function (name, b) { + var A, B, a = Str(this.attr(name) || ""), + el = this; + if (isNumeric(a) && isNumeric(b)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getNumber + }; + } + if (names[name] == "colour") { + A = Snap.color(a); + B = Snap.color(b); + return { + from: [A.r, A.g, A.b, A.opacity], + to: [B.r, B.g, B.b, B.opacity], + f: getColour + }; + } + if (name == "viewBox") { + A = this.attr(name).vb.split(" ").map(Number); + B = b.split(" ").map(Number); + return { + from: A, + to: B, + f: getViewBox + }; + } + if (name == "transform" || name == "gradientTransform" || name == "patternTransform") { + if (b instanceof Snap.Matrix) { + b = b.toTransformString(); + } + if (!Snap._.rgTransform.test(b)) { + b = Snap._.svgTransform2string(b); + } + return equaliseTransform(a, b, function () { + return el.getBBox(1); + }); + } + if (name == "d" || name == "path") { + A = Snap.path.toCubic(a, b); + return { + from: path2array(A[0]), + to: path2array(A[1]), + f: getPath(A[0]) + }; + } + if (name == "points") { + A = Str(a).split(Snap._.separator); + B = Str(b).split(Snap._.separator); + return { + from: A, + to: B, + f: function (val) { return val; } + }; + } + var aUnit = a.match(reUnit), + bUnit = Str(b).match(reUnit); + if (aUnit && arrayEqual(aUnit, bUnit)) { + return { + from: parseFloat(a), + to: parseFloat(b), + f: getUnit(aUnit) + }; + } else { + return { + from: this.asPX(name), + to: this.asPX(name, b), + f: getNumber + }; + } + }); +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + has = "hasOwnProperty", + supportsTouch = "createTouch" in glob.doc, + events = [ + "click", "dblclick", "mousedown", "mousemove", "mouseout", + "mouseover", "mouseup", "touchstart", "touchmove", "touchend", + "touchcancel" + ], + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + getScroll = function (xy, el) { + var name = xy == "y" ? "scrollTop" : "scrollLeft", + doc = el && el.node ? el.node.ownerDocument : glob.doc; + return doc[name in doc.documentElement ? "documentElement" : "body"][name]; + }, + preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = getScroll("y", element), + scrollX = getScroll("x", element); + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj || obj.contains(e.targetTouches[i].target)) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + var x = e.clientX + scrollX, + y = e.clientY + scrollY; + return fn.call(element, e, x, y); + }; + + if (type !== realName) { + obj.addEventListener(type, f, false); + } + + obj.addEventListener(realName, f, false); + + return function () { + if (type !== realName) { + obj.removeEventListener(type, f, false); + } + + obj.removeEventListener(realName, f, false); + return true; + }; + }, + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = getScroll("y"), + scrollX = getScroll("x"), + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches && e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id || dragi.el.node.contains(touch.target)) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + // glob.win.opera && parent.removeChild(node); + // node.style.display = "none"; + // o = dragi.el.paper.getElementByPoint(x, y); + // node.style.display = display; + // glob.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + // o && eve("snap.drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("snap.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + Snap.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("snap.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + eve.off("snap.drag.*." + dragi.el.id); + } + drag = []; + }; + /*\ + * Element.click + [ method ] + ** + * Adds a click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unclick + [ method ] + ** + * Removes a click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.dblclick + [ method ] + ** + * Adds a double click event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.undblclick + [ method ] + ** + * Removes a double click event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousedown + [ method ] + ** + * Adds a mousedown event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousedown + [ method ] + ** + * Removes a mousedown event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mousemove + [ method ] + ** + * Adds a mousemove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmousemove + [ method ] + ** + * Removes a mousemove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseout + [ method ] + ** + * Adds a mouseout event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseout + [ method ] + ** + * Removes a mouseout event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseover + [ method ] + ** + * Adds a mouseover event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseover + [ method ] + ** + * Removes a mouseover event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.mouseup + [ method ] + ** + * Adds a mouseup event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.unmouseup + [ method ] + ** + * Removes a mouseup event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchstart + [ method ] + ** + * Adds a touchstart event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchstart + [ method ] + ** + * Removes a touchstart event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchmove + [ method ] + ** + * Adds a touchmove event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchmove + [ method ] + ** + * Removes a touchmove event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchend + [ method ] + ** + * Adds a touchend event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchend + [ method ] + ** + * Removes a touchend event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + + /*\ + * Element.touchcancel + [ method ] + ** + * Adds a touchcancel event handler to the element + - handler (function) handler for the event + = (object) @Element + \*/ + /*\ + * Element.untouchcancel + [ method ] + ** + * Removes a touchcancel event handler from the element + - handler (function) handler for the event + = (object) @Element + \*/ + for (var i = events.length; i--;) { + (function (eventName) { + Snap[eventName] = elproto[eventName] = function (fn, scope) { + if (Snap.is(fn, "function")) { + this.events = this.events || []; + this.events.push({ + name: eventName, + f: fn, + unbind: addEvent(this.node || document, eventName, fn, scope || this) + }); + } else { + for (var i = 0, ii = this.events.length; i < ii; i++) if (this.events[i].name == eventName) { + try { + this.events[i].f.call(this); + } catch (e) {} + } + } + return this; + }; + Snap["un" + eventName] = + elproto["un" + eventName] = function (fn) { + var events = this.events || [], + l = events.length; + while (l--) if (events[l].name == eventName && + (events[l].f == fn || !fn)) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + /*\ + * Element.hover + [ method ] + ** + * Adds hover event handlers to the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + - icontext (object) #optional context for hover in handler + - ocontext (object) #optional context for hover out handler + = (object) @Element + \*/ + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + /*\ + * Element.unhover + [ method ] + ** + * Removes hover event handlers from the element + - f_in (function) handler for hover in + - f_out (function) handler for hover out + = (object) @Element + \*/ + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + // SIERRA unclear what _context_ refers to for starting, ending, moving the drag gesture. + // SIERRA Element.drag(): _x position of the mouse_: Where are the x/y values offset from? + // SIERRA Element.drag(): much of this member's doc appears to be duplicated for some reason. + // SIERRA Unclear about this sentence: _Additionally following drag events will be triggered: drag.start.<id> on start, drag.end.<id> on end and drag.move.<id> on every move._ Is there a global _drag_ object to which you can assign handlers keyed by an element's ID? + /*\ + * Element.drag + [ method ] + ** + * Adds event handlers for an element's drag gesture + ** + - onmove (function) handler for moving + - onstart (function) handler for drag start + - onend (function) handler for drag end + - mcontext (object) #optional context for moving handler + - scontext (object) #optional context for drag start handler + - econtext (object) #optional context for drag end handler + * Additionaly following `drag` events are triggered: `drag.start.<id>` on start, + * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element is dragged over another element + * `drag.over.<id>` fires as well. + * + * Start event and start handler are called in specified context or in context of the element with following parameters: + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * Move event and move handler are called in specified context or in context of the element with following parameters: + o dx (number) shift by x from the start point + o dy (number) shift by y from the start point + o x (number) x position of the mouse + o y (number) y position of the mouse + o event (object) DOM event object + * End event and end handler are called in specified context or in context of the element with following parameters: + o event (object) DOM event object + = (object) @Element + \*/ + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + var el = this; + if (!arguments.length) { + var origTransform; + return el.drag(function (dx, dy) { + this.attr({ + transform: origTransform + (origTransform ? "T" : "t") + [dx, dy] + }); + }, function () { + origTransform = this.transform().local; + }); + } + function start(e, x, y) { + (e.originalEvent || e).preventDefault(); + el._drag.x = x; + el._drag.y = y; + el._drag.id = e.identifier; + !drag.length && Snap.mousemove(dragMove).mouseup(dragUp); + drag.push({el: el, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("snap.drag.start." + el.id, onstart); + onmove && eve.on("snap.drag.move." + el.id, onmove); + onend && eve.on("snap.drag.end." + el.id, onend); + eve("snap.drag.start." + el.id, start_scope || move_scope || el, x, y, e); + } + function init(e, x, y) { + eve("snap.draginit." + el.id, el, e, x, y); + } + eve.on("snap.draginit." + el.id, start); + el._drag = {}; + draggable.push({el: el, start: start, init: init}); + el.mousedown(init); + return el; + }; + /* + * Element.onDragOver + [ method ] + ** + * Shortcut to assign event handler for `drag.over.<id>` event, where `id` is the element's `id` (see @Element.id) + - f (function) handler for event, first argument would be the element you are dragging over + \*/ + // elproto.onDragOver = function (f) { + // f ? eve.on("snap.drag.over." + this.id, f) : eve.unbind("snap.drag.over." + this.id); + // }; + /*\ + * Element.undrag + [ method ] + ** + * Removes all drag event handlers from the given element + \*/ + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].init); + draggable.splice(i, 1); + eve.unbind("snap.drag.*." + this.id); + eve.unbind("snap.draginit." + this.id); + } + !draggable.length && Snap.unmousemove(dragMove).unmouseup(dragUp); + return this; + }; +}); + +// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob) { + var elproto = Element.prototype, + pproto = Paper.prototype, + rgurl = /^\s*url\((.+)\)/, + Str = String, + $ = Snap._.$; + Snap.filter = {}; + /*\ + * Paper.filter + [ method ] + ** + * Creates a `<filter>` element + ** + - filstr (string) SVG fragment of filter provided as a string + = (object) @Element + * Note: It is recommended to use filters embedded into the page inside an empty SVG element. + > Usage + | var f = paper.filter('<feGaussianBlur stdDeviation="2"/>'), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + pproto.filter = function (filstr) { + var paper = this; + if (paper.type != "svg") { + paper = paper.paper; + } + var f = Snap.parse(Str(filstr)), + id = Snap._.id(), + width = paper.node.offsetWidth, + height = paper.node.offsetHeight, + filter = $("filter"); + $(filter, { + id: id, + filterUnits: "userSpaceOnUse" + }); + filter.appendChild(f.node); + paper.defs.appendChild(filter); + return new Element(filter); + }; + + eve.on("snap.util.getattr.filter", function () { + eve.stop(); + var p = $(this.node, "filter"); + if (p) { + var match = Str(p).match(rgurl); + return match && Snap.select(match[1]); + } + }); + eve.on("snap.util.attr.filter", function (value) { + if (value instanceof Element && value.type == "filter") { + eve.stop(); + var id = value.node.id; + if (!id) { + $(value.node, {id: value.id}); + id = value.id; + } + $(this.node, { + filter: Snap.url(id) + }); + } + if (!value || value == "none") { + eve.stop(); + this.node.removeAttribute("filter"); + } + }); + /*\ + * Snap.filter.blur + [ method ] + ** + * Returns an SVG markup string for the blur filter + ** + - x (number) amount of horizontal blur, in pixels + - y (number) #optional amount of vertical blur, in pixels + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.blur(5, 10)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.blur = function (x, y) { + if (x == null) { + x = 2; + } + var def = y == null ? x : [x, y]; + return Snap.format('\<feGaussianBlur stdDeviation="{def}"/>', { + def: def + }); + }; + Snap.filter.blur.toString = function () { + return this(); + }; + /*\ + * Snap.filter.shadow + [ method ] + ** + * Returns an SVG markup string for the shadow filter + ** + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - blur (number) #optional amount of blur + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - color (string) #optional color of the shadow + - opacity (number) #optional `0..1` opacity of the shadow + * which makes blur default to `4`. Or + - dx (number) #optional horizontal shift of the shadow, in pixels + - dy (number) #optional vertical shift of the shadow, in pixels + - opacity (number) #optional `0..1` opacity of the shadow + = (string) filter representation + > Usage + | var f = paper.filter(Snap.filter.shadow(0, 2, 3)), + | c = paper.circle(10, 10, 10).attr({ + | filter: f + | }); + \*/ + Snap.filter.shadow = function (dx, dy, blur, color, opacity) { + if (typeof blur == "string") { + color = blur; + opacity = color; + blur = 4; + } + if (typeof color != "string") { + opacity = color; + color = "#000"; + } + color = color || "#000"; + if (blur == null) { + blur = 4; + } + if (opacity == null) { + opacity = 1; + } + if (dx == null) { + dx = 0; + dy = 2; + } + if (dy == null) { + dy = dx; + } + color = Snap.color(color); + return Snap.format('<feGaussianBlur in="SourceAlpha" stdDeviation="{blur}"/><feOffset dx="{dx}" dy="{dy}" result="offsetblur"/><feFlood flood-color="{color}"/><feComposite in2="offsetblur" operator="in"/><feComponentTransfer><feFuncA type="linear" slope="{opacity}"/></feComponentTransfer><feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>', { + color: color, + dx: dx, + dy: dy, + blur: blur, + opacity: opacity + }); + }; + Snap.filter.shadow.toString = function () { + return this(); + }; + /*\ + * Snap.filter.grayscale + [ method ] + ** + * Returns an SVG markup string for the grayscale filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.grayscale = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {b} {h} 0 0 0 0 0 1 0"/>', { + a: 0.2126 + 0.7874 * (1 - amount), + b: 0.7152 - 0.7152 * (1 - amount), + c: 0.0722 - 0.0722 * (1 - amount), + d: 0.2126 - 0.2126 * (1 - amount), + e: 0.7152 + 0.2848 * (1 - amount), + f: 0.0722 - 0.0722 * (1 - amount), + g: 0.2126 - 0.2126 * (1 - amount), + h: 0.0722 + 0.9278 * (1 - amount) + }); + }; + Snap.filter.grayscale.toString = function () { + return this(); + }; + /*\ + * Snap.filter.sepia + [ method ] + ** + * Returns an SVG markup string for the sepia filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.sepia = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="matrix" values="{a} {b} {c} 0 0 {d} {e} {f} 0 0 {g} {h} {i} 0 0 0 0 0 1 0"/>', { + a: 0.393 + 0.607 * (1 - amount), + b: 0.769 - 0.769 * (1 - amount), + c: 0.189 - 0.189 * (1 - amount), + d: 0.349 - 0.349 * (1 - amount), + e: 0.686 + 0.314 * (1 - amount), + f: 0.168 - 0.168 * (1 - amount), + g: 0.272 - 0.272 * (1 - amount), + h: 0.534 - 0.534 * (1 - amount), + i: 0.131 + 0.869 * (1 - amount) + }); + }; + Snap.filter.sepia.toString = function () { + return this(); + }; + /*\ + * Snap.filter.saturate + [ method ] + ** + * Returns an SVG markup string for the saturate filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.saturate = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feColorMatrix type="saturate" values="{amount}"/>', { + amount: 1 - amount + }); + }; + Snap.filter.saturate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.hueRotate + [ method ] + ** + * Returns an SVG markup string for the hue-rotate filter + ** + - angle (number) angle of rotation + = (string) filter representation + \*/ + Snap.filter.hueRotate = function (angle) { + angle = angle || 0; + return Snap.format('<feColorMatrix type="hueRotate" values="{angle}"/>', { + angle: angle + }); + }; + Snap.filter.hueRotate.toString = function () { + return this(); + }; + /*\ + * Snap.filter.invert + [ method ] + ** + * Returns an SVG markup string for the invert filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.invert = function (amount) { + if (amount == null) { + amount = 1; + } +// <feColorMatrix type="matrix" values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0" color-interpolation-filters="sRGB"/> + return Snap.format('<feComponentTransfer><feFuncR type="table" tableValues="{amount} {amount2}"/><feFuncG type="table" tableValues="{amount} {amount2}"/><feFuncB type="table" tableValues="{amount} {amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: 1 - amount + }); + }; + Snap.filter.invert.toString = function () { + return this(); + }; + /*\ + * Snap.filter.brightness + [ method ] + ** + * Returns an SVG markup string for the brightness filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.brightness = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}"/><feFuncG type="linear" slope="{amount}"/><feFuncB type="linear" slope="{amount}"/></feComponentTransfer>', { + amount: amount + }); + }; + Snap.filter.brightness.toString = function () { + return this(); + }; + /*\ + * Snap.filter.contrast + [ method ] + ** + * Returns an SVG markup string for the contrast filter + ** + - amount (number) amount of filter (`0..1`) + = (string) filter representation + \*/ + Snap.filter.contrast = function (amount) { + if (amount == null) { + amount = 1; + } + return Snap.format('<feComponentTransfer><feFuncR type="linear" slope="{amount}" intercept="{amount2}"/><feFuncG type="linear" slope="{amount}" intercept="{amount2}"/><feFuncB type="linear" slope="{amount}" intercept="{amount2}"/></feComponentTransfer>', { + amount: amount, + amount2: .5 - amount / 2 + }); + }; + Snap.filter.contrast.toString = function () { + return this(); + }; +}); + +// Copyright (c) 2014 Adobe Systems Incorporated. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +Snap.plugin(function (Snap, Element, Paper, glob, Fragment) { + var box = Snap._.box, + is = Snap.is, + firstLetter = /^[^a-z]*([tbmlrc])/i, + toString = function () { + return "T" + this.dx + "," + this.dy; + }; + /*\ + * Element.getAlign + [ method ] + ** + * Returns shift needed to align the element relatively to given element. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object|string) Object in format `{dx: , dy: }` also has a string representation as a transformation string + > Usage + | el.transform(el.getAlign(el2, "top")); + * or + | var dy = el.getAlign(el2, "top").dy; + \*/ + Element.prototype.getAlign = function (el, way) { + if (way == null && is(el, "string")) { + way = el; + el = null; + } + el = el || this.paper; + var bx = el.getBBox ? el.getBBox() : box(el), + bb = this.getBBox(), + out = {}; + way = way && way.match(firstLetter); + way = way ? way[1].toLowerCase() : "c"; + switch (way) { + case "t": + out.dx = 0; + out.dy = bx.y - bb.y; + break; + case "b": + out.dx = 0; + out.dy = bx.y2 - bb.y2; + break; + case "m": + out.dx = 0; + out.dy = bx.cy - bb.cy; + break; + case "l": + out.dx = bx.x - bb.x; + out.dy = 0; + break; + case "r": + out.dx = bx.x2 - bb.x2; + out.dy = 0; + break; + default: + out.dx = bx.cx - bb.cx; + out.dy = 0; + break; + } + out.toString = toString; + return out; + }; + /*\ + * Element.align + [ method ] + ** + * Aligns the element relatively to given one via transformation. + * If no elements specified, parent `<svg>` container will be used. + - el (object) @optional alignment element + - way (string) one of six values: `"top"`, `"middle"`, `"bottom"`, `"left"`, `"center"`, `"right"` + = (object) this element + > Usage + | el.align(el2, "top"); + * or + | el.align("middle"); + \*/ + Element.prototype.align = function (el, way) { + return this.transform("..." + this.getAlign(el, way)); + }; +}); + +return Snap; +})); diff --git a/web/pgadmin/misc/templates/explain/js/explain.js b/web/pgadmin/misc/templates/explain/js/explain.js new file mode 100644 index 0000000..fd9a5e5 --- /dev/null +++ b/web/pgadmin/misc/templates/explain/js/explain.js @@ -0,0 +1,691 @@ +define ( + 'pgadmin.misc.explain', + ['jquery', 'underscore', 'underscore.string', 'pgadmin', 'backbone', 'snap.svg'], + function($, _, S, pgAdmin, Backbone, Snap) { + +pgAdmin = pgAdmin || window.pgAdmin || {}; +var pgExplain = pgAdmin.Explain; + +// Snap.svg plug-in to write multitext as image name +Snap.plugin(function (Snap, Element, Paper, glob) { + Paper.prototype.multitext = function (x, y, txt, max_width, attributes) { + var svg = Snap(), + abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + isWordBroken = false, + temp = svg.text(0, 0, abc); + + temp.attr(attributes); + + /* + * Find letter width in pixels and + * index from where the text should be broken + */ + var letter_width = temp.getBBox().width / abc.length, + word_break_index = Math.round((max_width / letter_width)) - 1; + + svg.remove(); + + var words = txt.split(" "), + width_so_far = 0, + lines=[], curr_line = '', + /* + * Function to divide string into multiple lines + * and store them in an array if it size crosses + * the max-width boundary. + */ + splitTextInMultiLine = function(leading, so_far, line) { + var l = line.length, + res = []; + + if (l == 0) + return res; + + if (so_far && (so_far + (l * letter_width) > max_width)) { + res.push(leading); + res = res.concat(splitTextInMultiLine('', 0, line)); + } else if (so_far) { + res.push(leading + ' ' + line); + } else { + if (leading) + res.push(leading); + if (line.length > word_break_index + 1) + res.push(line.slice(0, word_break_index) + '-'); + else + res.push(line); + res = res.concat(splitTextInMultiLine('', 0, line.slice(word_break_index))); + } + + return res; + }; + + for (var i = 0; i < words.length; i++) { + var tmpArr = splitTextInMultiLine( + curr_line, width_so_far, words[i] + ); + + if (curr_line) { + lines = lines.slice(0, lines.length - 2); + } + lines = lines.concat(tmpArr); + curr_line = lines[lines.length - 1]; + width_so_far = (curr_line.length * letter_width); + } + + // Create multiple tspan for each string in array + var t = this.text(x,y,lines).attr(attributes); + t.selectAll("tspan:nth-child(n+2)").attr({ + dy: "1.2em", + x: x + }); + return t; + }; +}); + +if (pgAdmin.Explain) + return pgAdmin.Explain; + +var pgExplain = pgAdmin.Explain = { + // Prefix path where images are stored + prefix: '{{ url_for('misc.static', filename='explain/img') }}/' +}; + +/* + * A map which is used to fetch the image to be drawn and + * text which will appear below it + */ +var imageMapper = { + "Aggregate" : { + "image":"ex_aggregate.png", "image_text":"Aggregate" + }, + 'Append' : { + "image":"ex_append.png","image_text":"Append" + }, + "Bitmap Index Scan" : function(data) { + return { + "image":"ex_bmp_index.png", "image_text":data['Index Name'] + }; + }, + "Bitmap Heap Scan" : function(data) { + return {"image":"ex_bmp_heap.png","image_text":data['Relation Name']}; +}, +"BitmapAnd" : {"image":"ex_bmp_and.png","image_text":"Bitmap AND"}, +"BitmapOr" : {"image":"ex_bmp_or.png","image_text":"Bitmap OR"}, +"CTE Scan" : {"image":"ex_cte_scan.png","image_text":"CTE Scan"}, +"Function Scan" : {"image":"ex_result.png","image_text":"Function Scan"}, +"Foreign Scan" : {"image":"ex_foreign_scan.png","image_text":"Foreign Scan"}, +"Gather" : {"image":"ex_gather_motion.png","image_text":"Gather"}, +"Group" : {"image":"ex_group.png","image_text":"Group"}, +"GroupAggregate": {"image":"ex_aggregate.png","image_text":"Group Aggregate"}, +"Hash" : {"image":"ex_hash.png","image_text":"Hash"}, +"Hash Join": function(data) { + if (!data['Join Type']) return {"image":"ex_join.png","image_text":"Join"}; + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_hash_anti_join.png","image_text":"Hash Anti Join"}; + case 'Semi': return {"image":"ex_hash_semi_join.png","image_text":"Hash Semi Join"}; + default: return {"image":"ex_hash.png","image_text":String("Hash " + data['Join Type'] + " Join" )}; + } +}, +"HashAggregate" : {"image":"ex_aggregate.png","image_text":"Hash Aggregate"}, +"Index Only Scan" : function(data) { + return {"image":"ex_index_only_scan.png","image_text":data['Index Name']}; +}, +"Index Scan" : function(data) { + return {"image":"ex_index_scan.png","image_text":data['Index Name']}; +}, +"Index Scan Backword" : {"image":"ex_index_scan.png","image_text":"Index Backward Scan"}, +"Limit" : {"image":"ex_limit.png","image_text":"Limit"}, +"LockRows" : {"image":"ex_lock_rows.png","image_text":"Lock Rows"}, +"Materialize" : {"image":"ex_materialize.png","image_text":"Materialize"}, +"Merge Append": {"image":"ex_merge_append.png","image_text":"Merge Append"}, +"Merge Join": function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_merge_anti_join.png","image_text":"Merge Anti Join"}; + case 'Semi': return {"image":"ex_merge_semi_join.png","image_text":"Merge Semi Join"}; + default: return {"image":"ex_merge.png","image_text":String("Merge " + data['Join Type'] + " Join" )}; + } +}, +"ModifyTable" : function(data) { + switch (data['Operaton']) { + case "insert": return { "image":"ex_insert.png", + "image_text":"Insert" + }; + case "update": return {"image":"ex_update.png","image_text":"Update"}; + case "Delete": return {"image":"ex_delete.png","image_text":"Delete"}; + } +}, +'Nested Loop' : function(data) { + switch(data['Join Type']) { + case 'Anti': return {"image":"ex_nested_loop_anti_join.png","image_text":"Nested Loop Anti Join"}; + case 'Semi': return {"image":"ex_nested_loop_semi_join.png","image_text":"Nested Loop Semi Join"}; + default: return {"image":"ex_nested.png","image_text":"Nested Loop " + data['Join Type'] + " Join"}; + } +}, +"Recursive Union" : {"image":"ex_recursive_union.png","image_text":"Recursive Union"}, +"Result" : {"image":"ex_result.png","image_text":"Result"}, +"Sample Scan" : {"image":"ex_scan.png","image_text":"Sample Scan"}, +"Scan" : {"image":"ex_scan.png","image_text":"Scan"}, +"Seek" : {"image":"ex_seek.png","image_text":"Seek"}, +"SetOp" : function(data) { + var strategy = data['Strategy'], + command = data['Command']; + + if(strategy == "Hashed") { + if(command.startsWith("Intersect")) { + if(command == "Intersect All") + return {"image":"ex_hash_setop_intersect_all.png","image_text":"Hashed Intersect All"}; + return {"image":"ex_hash_setop_intersect.png","image_text":"Hashed Intersect"}; + } + else if (command.startsWith("Except")) { + if(command == "Except All") + return {"image":"ex_hash_setop_except_all.png","image_text":"Hashed Except All"}; + return {"image":"ex_hash_setop_except.png","image_text":"Hash Except"}; + } + return {"image":"ex_hash_setop_unknown.png","image_text":"Hashed SetOp Unknown"}; + } + return {"image":"ex_setop.png","image_text":"SetOp"}; +}, +"Seq Scan": function(data) { + return {"image":"ex_scan.png","image_text":data['Relation Name']}; +}, +"Subquery Scan" : {"image":"ex_subplan.png","image_text":"SubQuery Scan"}, +"Sort" : {"image":"ex_sort.png","image_text":"Sort"}, +"Tid Scan" : {"image":"ex_tid_scan.png","image_text":"Tid Scan"}, +"Unique" : {"image":"ex_unique.png","image_text":"Unique"}, +"Values Scan" : {"image":"ex_values_scan.png","image_text":"Values Scan"}, +"WindowAgg" : {"image":"ex_window_aggregate.png","image_text":"Window Aggregate"}, +"WorkTable Scan" : {"image":"ex_worktable_scan.png","image_text":"WorkTable Scan"}, +"Undefined" : {"image":"ex_unknown.png","image_text":"Undefined"}, +} + +// Some predefined constants used to calculate image location and its border +var pWIDTH = pHEIGHT = 100. + IMAGE_WIDTH = IMAGE_HEIGHT = 50; +var offsetX = 200, + offsetY = 60; +var ARROW_WIDTH = 10, + ARROW_HEIGHT = 10, + DEFAULT_ARROW_SIZE = 2; +var TXT_ALLIGN = 5, + TXT_SIZE = "15px"; +var TOTAL_WIDTH = undefined, + TOTAL_HEIGHT = undefined; +var xMargin = 25, + yMargin = 25; +var MIN_ZOOM_FACTOR = 0.01, + MAX_ZOOM_FACTOR = 2, + INIT_ZOOM_FACTOR = 1; + ZOOM_RATIO = 0.05; + + +// Backbone model for each plan property of input JSON object +var PlanModel = Backbone.Model.extend({ + defaults: { + "Plans": [], + level: [], + "image": undefined, + "image_text": undefined, + xpos: undefined, + ypos: undefined, + width: pWIDTH, + height: pHEIGHT + }, + parse: function(data) { + var idx = 1, + lvl = data.level = data.level || [idx], + plans = [], + node_type = data['Node Type'], + // Calculating relative xpos of current node from top node + xpos = data.xpos = data.xpos - pWIDTH, + // Calculating relative ypos of current node from top node + ypos = data.ypos, + maxChildWidth = 0; + + data['width'] = pWIDTH; + data['height'] = pHEIGHT; + + /* + * calculating xpos, ypos, width and height if current node is a subplan + */ + if (data['Parent Relationship'] === "SubPlan") { + data['width'] += (xMargin * 2) + (xMargin / 2); + data['height'] += (yMargin * 2); + data['ypos'] += yMargin; + xpos -= xMargin; + ypos += yMargin; + } + + if(node_type.startsWith("(slice")) + node_type = node_type.substring(0,7); + + // Get the image information for current node + var mapperObj = (_.isFunction(imageMapper[node_type]) && + imageMapper[node_type].apply(undefined, [data])) || + imageMapper[node_type] || 'Undefined'; + + data["image"] = mapperObj["image"]; + data["image_text"] = mapperObj["image_text"]; + + // Start calculating xpos, ypos, width and height for child plans if any + if ('Plans' in data) { + + data['width'] += offsetX; + + _.each(data['Plans'], function(p) { + var level = _.clone(lvl), + plan = new PlanModel(); + + level.push(idx); + plan.set(plan.parse(_.extend( + p, { + "level": level, + xpos: xpos - offsetX, + ypos: ypos + }))); + + if (maxChildWidth < plan.get('width')) { + maxChildWidth = plan.get('width'); + } + + var childHeight = plan.get('height'); + + if (idx !== 1) { + data['height'] = data['height'] + childHeight + offsetY; + } else if (childHeight > data['height']) { + data['height'] = childHeight; + } + ypos += childHeight + offsetY; + + plans.push(plan); + idx++; + }); + } + + // Final Width and Height of current node + data['width'] += maxChildWidth; + data['Plans'] = plans; + + return data; + }, + + /* + * Required to parse and include non-default params of + * plan into backbone model + */ + toJSON: function(non_recursive) { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (non_recursive) { + delete res['Plans']; + } else { + var plans = []; + _.each(res['Plans'], function(p) { + plans.push(p.toJSON()); + }); + res['Plans'] = plans; + } + return res; + }, + + // Draw an arrow to parent node + drawPolyLine: function(g, startX, startY, endX, endY, opts, arrowOpts) { + // Calculate end point of first starting straight line (startx1, starty1) + // Calculate start point of 2nd straight line (endx1, endy1) + var midX1 = startX + ((endX - startX) / 3), + midX2 = startX + (2 * ((endX - startX) / 3)); + + //create arrow head + var arrow = g.polygon( + [0, ARROW_HEIGHT, + (ARROW_WIDTH / 2),ARROW_HEIGHT, + (ARROW_HEIGHT / 4), 0, + 0, ARROW_WIDTH] + ).transform("r90"); + var marker = arrow.marker( + 0, 0, ARROW_WIDTH, ARROW_HEIGHT, 0, (ARROW_WIDTH / 2) + ).attr(arrowOpts); + + // First straight line + g.line( + startX, startY, midX1, startY + ).attr(opts); + + // Diagonal line + g.line( + midX1-1, startY, midX2, endY + ).attr(opts); + + // Last straight line + var line = g.line( + midX2, endY, endX, endY + ).attr(opts); + line.attr({markerEnd: marker}) + }, + + // Draw image, its name and its tooltip + draw: function(s, xpos, ypos, pXpos, pYpos, graphContainer, toolTipContainer) { + var g = s.g(); + var currentXpos = xpos + this.get('xpos') , + currentYpos = ypos + this.get('ypos'), + isSubPlan = (this.get('Parent Relationship') === "SubPlan"); + + // Draw the subplan rectangle + if (isSubPlan) { + g.rect( + currentXpos - this.get('width') + pWIDTH + xMargin, + currentYpos - yMargin, + this.get('width') - xMargin, + this.get('height'), 5 + ).attr({ + stroke: '#444444', + 'strokeWidth': 1.2, + fill: 'gray', + fillOpacity: 0.2 + }); + + //provide subplan name + var text = g.text( + currentXpos + pWIDTH - ( this.get('width') / 2) - xMargin, + currentYpos + pHEIGHT - (this.get('height') / 2) - yMargin, + this.get('Subplan Name') + ).attr({ + fontSize: TXT_SIZE, "text-anchor":"start", + fill: 'red' + }); + } + + // Draw the actual image for current node + var image = g.image( + pgExplain.prefix + this.get('image'), + currentXpos + (pWIDTH - IMAGE_WIDTH) / 2, + currentYpos + (pHEIGHT - IMAGE_HEIGHT) / 2, + IMAGE_WIDTH, + IMAGE_HEIGHT + ); + + // Draw tooltip + var image_data = this.toJSON(); + image.mouseover(function(evt){ + + // Empty the tooltip content if it has any and add new data + toolTipContainer.empty(); + var tooltip = $('<table></table>',{ + class: "pgadmin-tooltip-table" + }).appendTo(toolTipContainer); + _.each(image_data, function(value,key) { + if(key !== 'image' && key !== 'Plans' && + key !== 'level' && key !== 'image' && + key !== 'image_text' && key !== 'xpos' && + key !== 'ypos' && key !== 'width' && + key !== 'height') { + tooltip.append( '<tr><td class="label explain-tooltip">' + key + '</td><td class="label explain-tooltip-val">' + value + '</td></tr>' ); + }; + }); + + var zoomFactor = graphContainer.data('zoom-factor'); + + // Calculate co-ordinates for tooltip + var toolTipX = ((currentXpos + pWIDTH) * zoomFactor - graphContainer.scrollLeft()); + var toolTipY = ((currentYpos + pHEIGHT) * zoomFactor - graphContainer.scrollTop()); + + // Recalculate x.y if tooltip is going out of screen + if(graphContainer.width() < (toolTipX + toolTipContainer[0].clientWidth)) + toolTipX -= (toolTipContainer[0].clientWidth + (pWIDTH*zoomFactor)); + //if(document.children[0].clientHeight < (toolTipY + toolTipContainer[0].clientHeight)) + if(graphContainer.height() < (toolTipY + toolTipContainer[0].clientHeight)) + toolTipY -= (toolTipContainer[0].clientHeight + ((pHEIGHT/2)*zoomFactor)); + + toolTipX = toolTipX < 0 ? 0 : (toolTipX); + toolTipY = toolTipY < 0 ? 0 : (toolTipY); + + // Show toolTip at respective x,y coordinates + toolTipContainer.css({'opacity': '0.8'}); + toolTipContainer.css('left', toolTipX); + toolTipContainer.css( 'top', toolTipY); + }); + + // Remove tooltip when mouse is out from node's area + image.mouseout(function() { + toolTipContainer.empty(); + toolTipContainer.css({'opacity': '0'}); + toolTipContainer.css('left', 0); + toolTipContainer.css( 'top', 0); + }); + + // Draw text below the node + var node_label = (this.get('Schema') == undefined ? + this.get('image_text') : + this.get('Schema')+"."+this.get('image_text')); + var label = g.g(); + g.multitext( + currentXpos + (pWIDTH / 2), + currentYpos + pHEIGHT - TXT_ALLIGN, + node_label, + 150, + {"font-size": TXT_SIZE ,"text-anchor":"middle"} + ); + + // Draw Arrow to parent only its not the first node + if (!_.isUndefined(pYpos)) { + var startx = currentXpos + pWIDTH; + var starty = currentYpos + (pHEIGHT / 2); + var endx = pXpos - ARROW_WIDTH; + var endy = pYpos + (pHEIGHT / 2); + var start_cost = this.get("Startup Cost"), + total_cost = this.get("Total Cost"); + var arrow_size = DEFAULT_ARROW_SIZE; + // Calculate arrow width according to cost of a particular plan + if(start_cost != undefined && total_cost != undefined) { + var arrow_size = Math.round(Math.log((start_cost+total_cost)/2 + start_cost)); + arrow_size = arrow_size < 1 ? 1 : arrow_size > 10 ? 10 : arrow_size; + } + + + var arrow_view_box = [0, 0, 2*ARROW_WIDTH, 2*ARROW_HEIGHT]; + var opts = {stroke: "#000000", strokeWidth: arrow_size + 1}, + subplanOpts = {stroke: "#866486", strokeWidth: arrow_size + 1}, + arrowOpts = {viewBox: arrow_view_box.join(" ")}; + + // Draw an arrow from current node to its parent + this.drawPolyLine( + g, startx, starty, endx, endy, + isSubPlan ? subplanOpts : opts, arrowOpts + ); + } + + var plans = this.get('Plans'); + + // Draw nodes for current plan's children + _.each(plans, function(p) { + p.draw(s, xpos, ypos, currentXpos, currentYpos, graphContainer, toolTipContainer); + }); + } +}); + +// Main backbone model to store JSON object +var MainPlanModel = Backbone.Model.extend({ + defaults: { + "Plan": undefined, + xpos: 0, + ypos: 0, + }, + initialize: function() { + this.set("Plan", new PlanModel()); + }, + + // Parse the JSON data and fetch its children plans + parse: function(data) { + if (data && 'Plan' in data) { + var plan = this.get("Plan"); + plan.set( + plan.parse( + _.extend( + data['Plan'], { + xpos: 0, + ypos: 0 + }))); + + data['xpos'] = 0; + data['ypos'] = 0; + data['width'] = plan.get('width') + (xMargin * 2); + data['height'] = plan.get('height') + (yMargin * 2); + + delete data['Plan']; + } + + return data; + }, + toJSON: function() { + var res = Backbone.Model.prototype.toJSON.apply(this, arguments); + + if (res.Plan) { + res.Plan = res.Plan.toJSON(); + } + + return res; + }, + draw: function(s, xpos, ypos, graphContainer, toolTipContainer) { + var g = s.g(); + + //draw the border + g.rect( + 0, 0, this.get('width') - 10, this.get('height') - 10, 5 + ).attr({ + stroke: '#FFEBCD', 'strokeWidth': 1.2, + fill: '#FFF8DC', fillOpacity: 0.5 + }); + + //Fetch total width, height + TOTAL_WIDTH = this.get('width'); + TOTAL_HEIGHT = this.get('height'); + var plan = this.get('Plan'); + + //Draw explain graph + plan.draw(g, xpos, ypos, undefined, undefined, graphContainer, toolTipContainer); + } +}); + +// Parse and draw full graphical explain +_.extend( + pgExplain, { + // Assumption container is a jQuery object + DrawJSONPlan: function(container, plan) { + var my_plans = []; + container.empty(); + var curr_zoom_factor = 1.0; + + var zoomArea =$('<div></div>', { + class: 'pg-explain-zoom-area btn-group', + role: 'group' + }).appendTo(container), + zoomInBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom in' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-search-plus' + })), + zoomToNormal = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom to original' + }).appendTo(zoomArea).append( + $('<i></i>',{ + class: 'fa fa-arrows-alt' + })) + zoomOutBtn = $('<button></button>', { + class: 'btn pg-explain-zoom-btn badge', + title: 'Zoom out' + }).appendTo(zoomArea).append( + $('<i></i>', { + class: 'fa fa-search-minus' + })); + + // Main div to be drawn all images on + var planDiv = $('<div></div>', + {class: "pgadmin-explain-container"} + ).appendTo(container), + // Div to draw tool-tip on + toolTip = $('<div></div>', + {id: "toolTip", + class: "pgadmin-explain-tooltip" + } + ).appendTo(container); + toolTip.empty(); + planDiv.data('zoom-factor', curr_zoom_factor); + + var w = 0, h = 0, + x = xMargin, h = yMargin; + + _.each(plan, function(p) { + var main_plan = new MainPlanModel(); + + // Parse JSON data to backbone model + main_plan.set(main_plan.parse(p)); + w = main_plan.get('width'); + h = main_plan.get('height'); + + var s = Snap(w, h), + $svg = $(s.node).detach(); + planDiv.append($svg); + main_plan.draw(s, w - xMargin, yMargin, planDiv, toolTip); + + var initPanelWidth = planDiv.width(), + initPanelHeight = planDiv.height(); + + /* + * Scale graph in case its width is bigger than panel width + * in which the graph is displayed + */ + if(initPanelWidth < w) { + var width_ratio = initPanelWidth / w; + + curr_zoom_factor = width_ratio; + curr_zoom_factor = curr_zoom_factor < MIN_ZOOM_FACTOR ? MIN_ZOOM_FACTOR : curr_zoom_factor; + curr_zoom_factor = curr_zoom_factor > INIT_ZOOM_FACTOR ? INIT_ZOOM_FACTOR : curr_zoom_factor; + + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + } + + zoomInBtn.on('click', function(e){ + curr_zoom_factor = ((curr_zoom_factor + ZOOM_RATIO) > MAX_ZOOM_FACTOR) ? MAX_ZOOM_FACTOR : (curr_zoom_factor + ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomInBtn.blur(); + }); + + zoomOutBtn.on('click', function(e) { + curr_zoom_factor = ((curr_zoom_factor - ZOOM_RATIO) < MIN_ZOOM_FACTOR) ? MIN_ZOOM_FACTOR : (curr_zoom_factor - ZOOM_RATIO); + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomOutBtn.blur(); + }); + + zoomToNormal.on('click', function(e) { + curr_zoom_factor = INIT_ZOOM_FACTOR; + var zoomInMatrix = new Snap.matrix(); + zoomInMatrix.scale(curr_zoom_factor, curr_zoom_factor); + + $svg.find('g').first().attr({transform: zoomInMatrix}); + $svg.attr({'width': w * curr_zoom_factor, 'height': h * curr_zoom_factor}); + planDiv.data('zoom-factor', curr_zoom_factor); + zoomToNormal.blur(); + }); + }); + + } + }); + + return pgExplain; +}); diff --git a/web/pgadmin/tools/datagrid/templates/datagrid/index.html b/web/pgadmin/tools/datagrid/templates/datagrid/index.html index ddb9d8f..1366017 100644 --- a/web/pgadmin/tools/datagrid/templates/datagrid/index.html +++ b/web/pgadmin/tools/datagrid/templates/datagrid/index.html @@ -66,10 +66,53 @@ body { </button> <ul class="dropdown-menu dropdown-menu"> <li> + <a id="btn-explain" href="#"> + <span>{{ _('Explain') }}</span> + </a> + </li> + <li> + <a id="btn-explain-analyze" href="#"> + <span>{{ _('Explain analyze') }}</span> + </a> + </li> + <li class="divider"></li> + <li class="dropdown-submenu dropdown-submenu"> + <a href="#">{{ _('Explain Options') }}</a> + <ul class="dropdown-menu"> + <li> + <a id="btn-explain-verbose" href="#" class="noclose"> + <i class="explain-verbose fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Verbose') }} </span> + </a> + </li> + <li> + <a id="btn-explain-costs" href="#" class="noclose"> + <i class="explain-costs fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Costs') }} </span> + </a> + </li> + <li> + <a id="btn-explain-buffers" href="#" class="noclose"> + <i class="explain-buffers fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Buffers') }} </span> + </a> + </li> + <li> + <a id="btn-explain-timing" href="#" class="noclose"> + <i class="explain-timing fa fa-check visibility-hidden" aria-hidden="true"></i> + <span> {{ _('Timing') }} </span> + </a> + </li> + </ul> + </li> + <li class="divider"></li> + <li> <a id="btn-auto-commit" href="#"> <i class="auto-commit fa fa-check" aria-hidden="true"></i> <span> {{ _('Auto-Commit') }} </span> </a> + </li> + <li> <a id="btn-auto-rollback" href="#"> <i class="auto-rollback fa fa-check visibility-hidden" aria-hidden="true"></i> <span> {{ _('Auto-Rollback') }} </span> diff --git a/web/pgadmin/tools/sqleditor/__init__.py b/web/pgadmin/tools/sqleditor/__init__.py index 3917f3d..8716090 100644 --- a/web/pgadmin/tools/sqleditor/__init__.py +++ b/web/pgadmin/tools/sqleditor/__init__.py @@ -17,7 +17,8 @@ from flask import Response, url_for, render_template, session, request from flask.ext.babel import gettext from flask.ext.security import login_required from pgadmin.utils import PgAdminModule -from pgadmin.utils.ajax import make_json_response, bad_request, success_return, internal_server_error +from pgadmin.utils.ajax import make_json_response, bad_request, \ + success_return, internal_server_error from pgadmin.utils.driver import get_driver from config import PG_DEFAULT_DRIVER from pgadmin.tools.sqleditor.command import QueryToolCommand @@ -66,6 +67,42 @@ class SqlEditorModule(PgAdminModule): category_label=gettext('Display') ) + self.explain_verbose = self.preference.register( + 'Explain Options', 'explain_verbose', + gettext("Verbose"), 'boolean', False, + category_label=gettext('Explain Options') + ) + + self.explain_costs = self.preference.register( + 'Explain Options', 'explain_costs', + gettext("Costs"), 'boolean', False, + category_label=gettext('Explain Options') + ) + + self.explain_buffers = self.preference.register( + 'Explain Options', 'explain_buffers', + gettext("Buffers"), 'boolean', False, + category_label=gettext('Explain Options') + ) + + self.explain_timing = self.preference.register( + 'Explain Options', 'explain_timing', + gettext("Timing"), 'boolean', False, + category_label=gettext('Explain Options') + ) + + self.auto_commit = self.preference.register( + 'Options', 'auto_commit', + gettext("Auto-Commit"), 'boolean', True, + category_label=gettext('Options') + ) + + self.auto_rollback = self.preference.register( + 'Options', 'auto_rollback', + gettext("Auto-Rollback"), 'boolean', False, + category_label=gettext('Options') + ) + blueprint = SqlEditorModule(MODULE_NAME, __name__, static_url_path='/static') @@ -277,6 +314,43 @@ def start_query_tool(trans_id): ) [email protected]('/query_tool/preferences', methods=["GET", "PUT"]) +@login_required +def get_preferences(): + """ + This method is used to get/put explain options from/to preferences + """ + if request.method == 'GET': + return make_json_response( + data={ + 'explain_verbose': blueprint.explain_verbose.get(), + 'explain_costs': blueprint.explain_costs.get(), + 'explain_buffers': blueprint.explain_buffers.get(), + 'explain_timing': blueprint.explain_timing.get(), + 'auto_commit': blueprint.auto_commit.get(), + 'auto_rollback': blueprint.auto_rollback.get() + } + ) + else: + data = None + if request.data: + data = json.loads(request.data.decode()) + else: + data = request.args or request.form + for k,v in data.items(): + v = bool(v) + if k == 'explain_verbose': + blueprint.explain_verbose.set(v) + elif k == 'explain_costs': + blueprint.explain_costs.set(v) + elif k == 'explain_buffers': + blueprint.explain_buffers.set(v) + elif k == 'explain_timing': + blueprint.explain_timing.set(v) + + return success_return() + + @blueprint.route('/poll/<int:trans_id>', methods=["GET"]) @login_required def poll(trans_id): @@ -739,6 +813,9 @@ def set_auto_commit(trans_id): # Call the set_auto_commit method of transaction object trans_obj.set_auto_commit(auto_commit) + # Set Auto commit in preferences + blueprint.auto_commit.set(bool(auto_commit)) + # As we changed the transaction object we need to # restore it and update the session variable. session_obj['command_obj'] = pickle.dumps(trans_obj, -1) @@ -774,6 +851,9 @@ def set_auto_rollback(trans_id): # Call the set_auto_rollback method of transaction object trans_obj.set_auto_rollback(auto_rollback) + # Set Auto Rollback in preferences + blueprint.auto_rollback.set(bool(auto_rollback)) + # As we changed the transaction object we need to # restore it and update the session variable. session_obj['command_obj'] = pickle.dumps(trans_obj, -1) diff --git a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css index dee3ea1..6db04cb 100644 --- a/web/pgadmin/tools/sqleditor/static/css/sqleditor.css +++ b/web/pgadmin/tools/sqleditor/static/css/sqleditor.css @@ -236,3 +236,10 @@ .CodeMirror-foldgutter-folded:after { content: "\25B6"; } + + +.sql-editor-explain { + height: 100%; + width: 100%; + overflow: auto; +} diff --git a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js index ee533a1..a780809 100644 --- a/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js +++ b/web/pgadmin/tools/sqleditor/templates/sqleditor/js/sqleditor.js @@ -1,10 +1,10 @@ define( - ['jquery', 'underscore', 'alertify', 'pgadmin', 'backbone', 'backgrid', 'codemirror', - 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/selection/active-line', + ['jquery', 'underscore', 'underscore.string', 'alertify', 'pgadmin', 'pgadmin.misc.explain', + 'backbone', 'backgrid', 'codemirror', 'codemirror/mode/sql/sql', 'codemirror/addon/selection/mark-selection', 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', 'codemirror/addon/fold/pgadmin-sqlfoldcode', - 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', 'backgrid.filter', - 'bootstrap', 'pgadmin.browser', 'wcdocker'], - function($, _, alertify, pgAdmin, Backbone, Backgrid, CodeMirror) { + 'codemirror/addon/selection/active-line', 'backgrid.select.all', 'backbone.paginator', 'backgrid.paginator', + 'backgrid.filter', 'bootstrap', 'pgadmin.browser', 'wcdocker'], + function($, _, S, alertify, pgAdmin, pgExplain, Backbone, Backgrid, CodeMirror) { // Some scripts do export their object in the window only. // Generally the one, which do no have AMD support. @@ -161,6 +161,12 @@ define( "click #btn-auto-rollback": "on_auto_rollback", "click #btn-clear-history": "on_clear_history", "click .noclose": 'do_not_close_menu', + "click #btn-explain": "on_explain", + "click #btn-explain-analyze": "on_explain_analyze", + "click #btn-explain-verbose": "on_explain_verbose", + "click #btn-explain-costs": "on_explain_costs", + "click #btn-explain-buffers": "on_explain_buffers", + "click #btn-explain-timing": "on_explain_timing", "change .limit": "on_limit_change" }, @@ -205,7 +211,6 @@ define( isPrivate: true }); - //sql_panel.load(main_docker); sql_panel.load(main_docker); var sql_panel_obj = main_docker.addPanel('sql_panel', wcDocker.DOCK.TOP); @@ -247,7 +252,7 @@ define( height:'100%', isCloseable: false, isPrivate: true, - content: '<div class="sql-editor-explian"></div>' + content: '<div class="sql-editor-explain"></div>' }) var messages = new pgAdmin.Browser.Panel({ @@ -283,6 +288,87 @@ define( self.history_panel = main_docker.addPanel('history', wcDocker.DOCK.STACKED, self.data_output_panel); self.render_history_grid(); + + // Get auto-rollback/auto-commit and explain options from preferences + self.get_preferences(); + }, + + /* + * This function get explain options and auto rollback/auto commit + * values from preferences + */ + get_preferences: function() { + $.ajax({ + url: "{{ url_for('sqleditor.index') }}" + "query_tool/preferences" , + method: 'GET', + async: false, + success: function(res) { + if (res.data) { + self.explain_verbose = res.data.explain_verbose; + self.explain_costs = res.data.explain_costs; + self.explain_buffers = res.data.explain_buffers; + self.explain_timing = res.data.explain_timing; + self.auto_commit = res.data.auto_commit; + self.auto_rollback = res.data.auto_rollback; + } + else { + self.explain_verbose = false; + self.explain_costs = false; + self.explain_buffers = false; + self.explain_timing = false; + self.auto_commit = true; + self.auto_rollback = false; + } + }, + error: function(e) { + self.explain_verbose = false; + self.explain_costs = false; + self.explain_buffers = false; + self.explain_timing = false; + self.auto_commit = true; + self.auto_rollback = false; + } + }); + + // Set Auto-commit and auto-rollback on query editor + if (self.auto_commit && + $('.auto-commit').hasClass('visibility-hidden') === true) + $('.auto-commit').removeClass('visibility-hidden'); + else { + $('.auto-commit').addClass('visibility-hidden'); + } + if (self.auto_rollback && + $('.auto-rollback').hasClass('visibility-hidden') === true) + $('.auto-rollback').removeClass('visibility-hidden'); + else { + $('.auto-rollback').addClass('visibility-hidden'); + } + + // Set explain options on query editor + if (self.explain_verbose && + $('.explain-verbose').hasClass('visibility-hidden') === true) + $('.explain-verbose').removeClass('visibility-hidden'); + else { + $('.explain-verbose').addClass('visibility-hidden'); + } + if (self.explain_costs && + $('.explain-costs').hasClass('visibility-hidden') === true) + $('.explain-costs').removeClass('visibility-hidden'); + else { + $('.explain-costs').addClass('visibility-hidden'); + } + if (self.explain_buffers && + $('.explain-buffers').hasClass('visibility-hidden') === true) + $('.explain-buffers').removeClass('visibility-hidden'); + else { + $('.explain-buffers').addClass('visibility-hidden'); + } + if (self.explain_timing && + $('.explain-timing').hasClass('visibility-hidden') === true) + $('.explain-timing').removeClass('visibility-hidden'); + else { + $('.explain-timing').addClass('visibility-hidden'); + } }, /* This function is responsible to create and render the @@ -639,6 +725,79 @@ define( self.handler ); }, + + // Callback function for explain button click. + on_explain: function() { + var self = this; + + // Trigger the explain signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain', + self, + self.handler + ); + }, + + // Callback function for explain analyze button click. + on_explain_analyze: function() { + var self = this; + + // Trigger the explain analyze signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-analyze', + self, + self.handler + ); + }, + + // Callback function for explain option "verbose" button click + on_explain_verbose: function() { + var self = this; + + // Trigger the explain "verbose" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-verbose', + self, + self.handler + ); + }, + + // Callback function for explain option "costs" button click + on_explain_costs: function() { + var self = this; + + // Trigger the explain "costs" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-costs', + self, + self.handler + ); + }, + + // Callback function for explain option "buffers" button click + on_explain_buffers: function() { + var self = this; + + // Trigger the explain "buffers" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-buffers', + self, + self.handler + ); + }, + + // Callback function for explain option "timing" button click + on_explain_timing: function() { + var self = this; + + // Trigger the explain "timing" signal to the SqlEditorController class + self.handler.trigger( + 'pgadmin-sqleditor:button:explain-timing', + self, + self.handler + ); + }, + do_not_close_menu: function(ev) { ev.stopPropagation(); } @@ -671,6 +830,10 @@ define( self.items_per_page = 25; self.rows_affected = 0; self.marked_line_no = 0; + self.explain_verbose = false; + self.explain_costs = false; + self.explain_buffers = false; + self.explain_timing = false; // We do not allow to call the start multiple times. if (self.gridView) @@ -703,6 +866,12 @@ define( self.on('pgadmin-sqleditor:button:download', self._download, self); self.on('pgadmin-sqleditor:button:auto_rollback', self._auto_rollback, self); self.on('pgadmin-sqleditor:button:auto_commit', self._auto_commit, self); + self.on('pgadmin-sqleditor:button:explain', self._explain, self); + self.on('pgadmin-sqleditor:button:explain-analyze', self._explain_analyze, self); + self.on('pgadmin-sqleditor:button:explain-verbose', self._explain_verbose, self); + self.on('pgadmin-sqleditor:button:explain-costs', self._explain_costs, self); + self.on('pgadmin-sqleditor:button:explain-buffers', self._explain_buffers, self); + self.on('pgadmin-sqleditor:button:explain-timing', self._explain_timing, self); if (self.is_query_tool) { self.gridView.query_tool_obj.refresh(); @@ -743,6 +912,7 @@ define( self.gridView.query_tool_obj.setValue(res.data.sql); self.query = res.data.sql; + /* If filter is applied then remove class 'btn-default' * and add 'btn-warning' to change the colour of the button. */ @@ -880,6 +1050,7 @@ define( self.cell_selected = false; self.selected_model = null; self.changedModels = []; + $('.sql-editor-explain').empty(); // Stop listening to all the events if (self.collection) { @@ -948,10 +1119,26 @@ define( var message = 'Total query runtime: ' + self.total_time + '\n' + self.rows_affected + ' rows retrieved.'; $('.sql-editor-message').text(message); - // Add the data to the collection and render the grid. - self.collection.add(data.result, {parse: true}); - self.gridView.render_grid(self.collection, self.columns); - self.gridView.data_output_panel.focus(); + /* Add the data to the collection and render the grid. + * In case of Explain draw the graph on explain panel + * and add json formatted data to collection and render. + */ + var explain_data_array = []; + if(data.result && + 'QUERY PLAN' in data.result[0] && + _.isObject(data.result[0]['QUERY PLAN'])) { + var explain_data = {'QUERY PLAN' : JSON.stringify(data.result[0]['QUERY PLAN'], null, 2)}; + explain_data_array.push(explain_data); + self.gridView.explain_panel.focus(); + pgExplain.DrawJSONPlan($('.sql-editor-explain'), data.result[0]['QUERY PLAN']); + self.collection.add(explain_data_array, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + } + else { + self.collection.add(data.result, {parse: true}); + self.gridView.render_grid(self.collection, self.columns); + self.gridView.data_output_panel.focus(); + } // Hide the loading icon self.trigger('pgadmin-sqleditor:loading-icon:hide'); @@ -1700,16 +1887,11 @@ define( // This function will fetch the sql query from the text box // and execute the query. - _execute: function () { + _execute: function (explain_prefix) { var self = this, sql = '', history_msg = ''; - self.trigger( - 'pgadmin-sqleditor:loading-icon:show', - '{{ _('Initializing query execution.') }}' - ); - /* If code is selected in the code mirror then execute * the selected part else execute the complete code. */ @@ -1719,6 +1901,17 @@ define( else sql = self.gridView.query_tool_obj.getValue(); + // If it is an empty query, do nothing. + if (sql.length <= 0) return; + + self.trigger( + 'pgadmin-sqleditor:loading-icon:show', + '{{ _('Initializing the query execution!') }}' + ); + + if (explain_prefix != undefined) + sql = explain_prefix + ' ' + sql; + self.query_start_time = new Date(); self.query = sql; self.rows_affected = 0; @@ -2037,6 +2230,172 @@ define( alertify.alert('Auto Commit Error', msg); } }); + }, + + // This function will + _explain: function() { + var self = this; + var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + // No need to check for buffers and timing option value in explain + var explain_query = 'EXPLAIN (FORMAT JSON, ANALYZE OFF, VERBOSE %s, COSTS %s, BUFFERS OFF, TIMING OFF) '; + explain_query = S(explain_query).sprintf(verbose, costs).value(); + self._execute(explain_query); + }, + + // This function will + _explain_analyze: function() { + var self = this;var verbose = $('.explain-verbose').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var costs = $('.explain-costs').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var buffers = $('.explain-buffers').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + var timing = $('.explain-timing').hasClass('visibility-hidden') ? 'OFF' : 'ON'; + + var explain_query = 'Explain (FORMAT JSON, ANALYZE ON, VERBOSE %s, COSTS %s, BUFFERS %s, TIMING %s) '; + explain_query = S(explain_query).sprintf(verbose, costs, buffers, timing).value(); + self._execute(explain_query); + }, + + // This function will toggle "verbose" option in explain + _explain_verbose: function() { + if ($('.explain-verbose').hasClass('visibility-hidden') === true) { + $('.explain-verbose').removeClass('visibility-hidden'); + self.explain_verbose = true; + } + else { + $('.explain-verbose').addClass('visibility-hidden'); + self.explain_verbose = false; + } + + // Set this option in preferences + var data = { + 'explain_verbose': self.explain_verbose + }; + $.ajax({ + url: "{{ url_for('sqleditor.index') }}" + "query_tool/preferences" , + method: 'PUT', + contentType: "application/json", + data: JSON.stringify(data), + success: function(res) { + if(res.success == undefined || !res.success) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting verbose option in explain') }}' + ); + } + }, + error: function(e) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting verbose option in explain') }}' + ); + return; + } + }); + }, + + // This function will toggle "costs" option in explain + _explain_costs: function() { + if ($('.explain-costs').hasClass('visibility-hidden') === true) { + $('.explain-costs').removeClass('visibility-hidden'); + self.explain_costs = true; + } + else { + $('.explain-costs').addClass('visibility-hidden'); + self.explain_costs = false; + } + + // Set this option in preferences + var data = { + 'explain_costs': self.explain_costs + }; + $.ajax({ + url: "{{ url_for('sqleditor.index') }}" + "query_tool/preferences" , + method: 'PUT', + contentType: "application/json", + data: JSON.stringify(data), + success: function(res) { + if(res.success == undefined || !res.success) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting costs option in explain') }}' + ); + } + }, + error: function(e) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting costs option in explain') }}' + ); + } + }); + }, + + // This function will toggle "buffers" option in explain + _explain_buffers: function() { + if ($('.explain-buffers').hasClass('visibility-hidden') === true) { + $('.explain-buffers').removeClass('visibility-hidden'); + self.explain_buffers = true; + } + else { + $('.explain-buffers').addClass('visibility-hidden'); + self.explain_buffers = false; + } + + // Set this option in preferences + var data = { + 'explain_buffers': self.explain_buffers + }; + $.ajax({ + url: "{{ url_for('sqleditor.index') }}" + "query_tool/preferences" , + method: 'PUT', + contentType: "application/json", + data: JSON.stringify(data), + success: function(res) { + if(res.success == undefined || !res.success) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting buffers option in explain') }}' + ); + } + }, + error: function(e) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting buffers option in explain') }}' + ); + } + }); + + }, + + // This function will toggle "timing" option in explain + _explain_timing: function() { + if ($('.explain-timing').hasClass('visibility-hidden') === true) { + $('.explain-timing').removeClass('visibility-hidden'); + self.explain_timing = true; + } + else { + $('.explain-timing').addClass('visibility-hidden'); + self.explain_timing = true; + } + // Set this option in preferences + var data = { + 'explain_timing': self.explain_timing + }; + $.ajax({ + url: "{{ url_for('sqleditor.index') }}" + "query_tool/preferences" , + method: 'PUT', + contentType: "application/json", + data: JSON.stringify(data), + success: function(res) { + if(res.success == undefined || !res.success) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting timing option in explain') }}' + ); + } + }, + error: function(e) { + alertify.alert('Explain options error', + '{{ _('Error occurred while setting timing option in explain') }}' + ); + } + }); + } } ); ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-13 10:31 Sanket Mehta <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 1 reply; 10+ messages in thread From: Sanket Mehta @ 2016-05-13 10:31 UTC (permalink / raw) To: Akshay Joshi <[email protected]>; +Cc: pgadmin-hackers Hi, Apart from resolving all the issues mentioned in previous mail, All the explain options and auto rollback/auto commit are also added to preferences dialog. Any change to explains options or auto-rollback/auto-commit in sql editor will directly reflect its corresponding option in preference dialog. Regards, Sanket Mehta Sr Software engineer Enterprisedb On Fri, May 13, 2016 at 3:55 PM, Sanket Mehta <[email protected] > wrote: > Hi, > > Revised patch is attached > Response in inline. > > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > > On Tue, May 10, 2016 at 2:54 PM, Akshay Joshi < > [email protected]> wrote: > >> Hi Sanket >> >> On Tue, May 10, 2016 at 12:21 PM, Sanket Mehta <sanket.mehta@enterprisedb >> .com> wrote: >> >>> Hi, >>> >>> As previous patch was not applicable to latest pgadmin4 source code, >>> here is the new patch accommodating latest code. >>> Please do review it and send comments. >>> >> >> Following is my review comments >> >> - Remove Demo and sample code which you have used for testing before >> integration. >> >> Fixes > >> >> - Facing issue to open QueryTool as there is some problem in require >> module. >> >> Fixed > >> >> - Please add 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', >> 'codemirror/addon/fold/pgadmin-sqlfoldcode' files which has been >> removed from your patch. >> >> Fixed > >> >> - Remove below code from sqleditor.js which is duplicated in _execute >> function >> - >> - self.trigger( >> - 'pgadmin-sqleditor:loading-icon:show', >> - '{{ _('Initializing the query execution!') }}' >> - ) >> >> Fixed > >> >> - Clear the existing contents of the Explain tab when execute the >> query without explain. >> >> Fixed > >> >> - If schema name is exists then please prefix the schema name to the >> node. >> >> Fixed > >> >> - Please check the data is available before working on it in sqleditor >> .js at line no 1043 inside _render(). In case of "View Data" it >> throws an error. >> >> Fixed > >> >> >>> >>> Regards, >>> Sanket Mehta >>> Sr Software engineer >>> Enterprisedb >>> >>> On Mon, May 9, 2016 at 11:56 PM, Sanket Mehta < >>> [email protected]> wrote: >>> >>>> Hi, >>>> >>>> Please ignore previous patch as there was an error in it. >>>> >>>> Error: >>>> Tooltip was not getting disappear when user moves cursor out of image. >>>> >>>> I have attached a proper patch with this mail. >>>> Please consider it for testing. >>>> >>>> Regards, >>>> Sanket Mehta >>>> Sr Software engineer >>>> Enterprisedb >>>> >>>> On Mon, May 9, 2016 at 8:49 PM, Sanket Mehta < >>>> [email protected]> wrote: >>>> >>>>> Hi, >>>>> >>>>> PFA revised patch according to Ashesh's comments. >>>>> Please find my response inline. >>>>> >>>>> I am currently adding minimap feature in graphical explain. >>>>> I will send a new patch for the same. >>>>> >>>>> Regards, >>>>> Sanket Mehta >>>>> Sr Software engineer >>>>> Enterprisedb >>>>> >>>>> On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi Sanket, >>>>>> >>>>>> Please find the review comments. >>>>>> - Please add the missing 'explain.css'. >>>>>> >>>>> Done >>>>> >>>>>> - The application should be smart enough to handle conflict in >>>>>> options. >>>>>> i.e. >>>>>> Buffer is not a valid options without EXPLAIN ANALYZE. >>>>>> >>>>> Done >>>>> >>>>>> - A statement having EXPLAIN keywords with different format should at >>>>>> least render the output in the data-grid. >>>>>> i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; >>>>>> >>>>> Done >>>>> >>>>>> - Please use the keywords used in the EXPLAIN statement in capital. >>>>>> >>>>> Done >>>>> >>>>>> - Explain should not work with empty string. >>>>>> >>>>> Done >>>>> >>>>>> - Font size in the tooltip is very small. >>>>>> >>>>> Done >>>>> >>>>>> >>>>>> >>>>> - Smoothing the zoom functionality. >>>>>> >>>>> Minimap will be added and zoom functionality will be removed. So it is >>>>> ignored. >>>>> >>>>> - Arrow marker is hardly visible. >>>>>> >>>>> Done. >>>>> >>>>>> >>>>>> >>>>>> -- >>>>>> >>>>>> Thanks & Regards, >>>>>> >>>>>> Ashesh Vashi >>>>>> EnterpriseDB INDIA: Enterprise PostgreSQL Company >>>>>> <http://www.enterprisedb.com; >>>>>> >>>>>> >>>>>> *http://www.linkedin.com/in/asheshvashi* >>>>>> <http://www.linkedin.com/in/asheshvashi; >>>>>> >>>>>> On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi, >>>>>>> >>>>>>> This patch includes the patch sent earlier for stand alone graphical >>>>>>> explain. >>>>>>> >>>>>>> And also "horizontal lines are not proper" bug is fixed in the same >>>>>>> which was reported by Dave in previous patch. >>>>>>> >>>>>>> Regards, >>>>>>> Sanket Mehta >>>>>>> Sr Software engineer >>>>>>> Enterprisedb >>>>>>> >>>>>>> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi Team, >>>>>>>> >>>>>>>> PFA the first patch for graphical explain integrated in sql editor. >>>>>>>> >>>>>>>> Below are the few things which are different from previous patch >>>>>>>> which was sent for stand alone graphical explain. >>>>>>>> >>>>>>>> - Now user can select Explain/Explain Analyze with four optional >>>>>>>> properties (Verbose, costs, timing and buffers) >>>>>>>> >>>>>>>> - Initially graph will be scale (according to only its width not >>>>>>>> height) to fit to screen so no blank space will be there in case of very >>>>>>>> large graph. >>>>>>>> >>>>>>>> - Along with zoom in/out button, "zoom to original" button is also >>>>>>>> provided, by clicking on which graph will be scale to its original size >>>>>>>> (not same as initial one which is according to screen size). >>>>>>>> >>>>>>>> Please do review this patch and let me know in case you have any >>>>>>>> comments. >>>>>>>> >>>>>>>> >>>>>>>> Regards, >>>>>>>> Sanket Mehta >>>>>>>> Sr Software engineer >>>>>>>> Enterprisedb >>>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>> >>> >>> -- >>> Sent via pgadmin-hackers mailing list ([email protected]) >>> To make changes to your subscription: >>> http://www.postgresql.org/mailpref/pgadmin-hackers >>> >>> >> >> >> -- >> *Akshay Joshi* >> *Principal Software Engineer * >> >> >> >> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >> > > ^ permalink raw reply [nested|flat] 10+ messages in thread
* Re: PATCH: Graphincal explain integrated in sql editor @ 2016-05-15 19:41 Ashesh Vashi <[email protected]> parent: Sanket Mehta <[email protected]> 0 siblings, 0 replies; 10+ messages in thread From: Ashesh Vashi @ 2016-05-15 19:41 UTC (permalink / raw) To: Sanket Mehta <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers On Fri, May 13, 2016 at 4:01 PM, Sanket Mehta <[email protected] > wrote: > Hi, > > Apart from resolving all the issues mentioned in previous mail, All the > explain options and auto rollback/auto commit are also added to preferences > dialog. > Any change to explains options or auto-rollback/auto-commit in sql editor > will directly reflect its corresponding option in preference dialog. > Thanks - committed. Looking forward to a minimap kind of functionality for better zooming, and sliding functionalities integrated with the explain module. Also - added nice to have TODO list for the 'Graphical Explain' module. -- Thanks & Regards, Ashesh Vashi EnterpriseDB INDIA: Enterprise PostgreSQL Company <http://www.enterprisedb.com/; *http://www.linkedin.com/in/asheshvashi* <http://www.linkedin.com/in/asheshvashi; > > > Regards, > Sanket Mehta > Sr Software engineer > Enterprisedb > > On Fri, May 13, 2016 at 3:55 PM, Sanket Mehta < > [email protected]> wrote: > >> Hi, >> >> Revised patch is attached >> Response in inline. >> >> >> Regards, >> Sanket Mehta >> Sr Software engineer >> Enterprisedb >> >> On Tue, May 10, 2016 at 2:54 PM, Akshay Joshi < >> [email protected]> wrote: >> >>> Hi Sanket >>> >>> On Tue, May 10, 2016 at 12:21 PM, Sanket Mehta <sanket.mehta@ >>> enterprisedb.com> wrote: >>> >>>> Hi, >>>> >>>> As previous patch was not applicable to latest pgadmin4 source code, >>>> here is the new patch accommodating latest code. >>>> Please do review it and send comments. >>>> >>> >>> Following is my review comments >>> >>> - Remove Demo and sample code which you have used for testing before >>> integration. >>> >>> Fixes >> >>> >>> - Facing issue to open QueryTool as there is some problem in require >>> module. >>> >>> Fixed >> >>> >>> - Please add 'codemirror/addon/fold/foldgutter', 'codemirror/addon/fold/foldcode', >>> 'codemirror/addon/fold/pgadmin-sqlfoldcode' files which has been >>> removed from your patch. >>> >>> Fixed >> >>> >>> - Remove below code from sqleditor.js which is duplicated in >>> _execute function >>> - >>> - self.trigger( >>> - 'pgadmin-sqleditor:loading-icon:show', >>> - '{{ _('Initializing the query execution!') }}' >>> - ) >>> >>> Fixed >> >>> >>> - Clear the existing contents of the Explain tab when execute the >>> query without explain. >>> >>> Fixed >> >>> >>> - If schema name is exists then please prefix the schema name to the >>> node. >>> >>> Fixed >> >>> >>> - Please check the data is available before working on it in >>> sqleditor.js at line no 1043 inside _render(). In case of "View >>> Data" it throws an error. >>> >>> Fixed >> >>> >>> >>>> >>>> Regards, >>>> Sanket Mehta >>>> Sr Software engineer >>>> Enterprisedb >>>> >>>> On Mon, May 9, 2016 at 11:56 PM, Sanket Mehta < >>>> [email protected]> wrote: >>>> >>>>> Hi, >>>>> >>>>> Please ignore previous patch as there was an error in it. >>>>> >>>>> Error: >>>>> Tooltip was not getting disappear when user moves cursor out of image. >>>>> >>>>> I have attached a proper patch with this mail. >>>>> Please consider it for testing. >>>>> >>>>> Regards, >>>>> Sanket Mehta >>>>> Sr Software engineer >>>>> Enterprisedb >>>>> >>>>> On Mon, May 9, 2016 at 8:49 PM, Sanket Mehta < >>>>> [email protected]> wrote: >>>>> >>>>>> Hi, >>>>>> >>>>>> PFA revised patch according to Ashesh's comments. >>>>>> Please find my response inline. >>>>>> >>>>>> I am currently adding minimap feature in graphical explain. >>>>>> I will send a new patch for the same. >>>>>> >>>>>> Regards, >>>>>> Sanket Mehta >>>>>> Sr Software engineer >>>>>> Enterprisedb >>>>>> >>>>>> On Mon, Apr 25, 2016 at 4:36 PM, Ashesh Vashi < >>>>>> [email protected]> wrote: >>>>>> >>>>>>> Hi Sanket, >>>>>>> >>>>>>> Please find the review comments. >>>>>>> - Please add the missing 'explain.css'. >>>>>>> >>>>>> Done >>>>>> >>>>>>> - The application should be smart enough to handle conflict in >>>>>>> options. >>>>>>> i.e. >>>>>>> Buffer is not a valid options without EXPLAIN ANALYZE. >>>>>>> >>>>>> Done >>>>>> >>>>>>> - A statement having EXPLAIN keywords with different format should >>>>>>> at least render the output in the data-grid. >>>>>>> i.e. EXPLAIN (FORMAT xml) SELECT * FROM xyz; >>>>>>> >>>>>> Done >>>>>> >>>>>>> - Please use the keywords used in the EXPLAIN statement in capital. >>>>>>> >>>>>> Done >>>>>> >>>>>>> - Explain should not work with empty string. >>>>>>> >>>>>> Done >>>>>> >>>>>>> - Font size in the tooltip is very small. >>>>>>> >>>>>> Done >>>>>> >>>>>>> >>>>>>> >>>>>> - Smoothing the zoom functionality. >>>>>>> >>>>>> Minimap will be added and zoom functionality will be removed. So it >>>>>> is ignored. >>>>>> >>>>>> - Arrow marker is hardly visible. >>>>>>> >>>>>> Done. >>>>>> >>>>>>> >>>>>>> >>>>>>> -- >>>>>>> >>>>>>> Thanks & Regards, >>>>>>> >>>>>>> Ashesh Vashi >>>>>>> EnterpriseDB INDIA: Enterprise PostgreSQL Company >>>>>>> <http://www.enterprisedb.com; >>>>>>> >>>>>>> >>>>>>> *http://www.linkedin.com/in/asheshvashi* >>>>>>> <http://www.linkedin.com/in/asheshvashi; >>>>>>> >>>>>>> On Mon, Apr 25, 2016 at 3:06 PM, Sanket Mehta < >>>>>>> [email protected]> wrote: >>>>>>> >>>>>>>> Hi, >>>>>>>> >>>>>>>> This patch includes the patch sent earlier for stand alone >>>>>>>> graphical explain. >>>>>>>> >>>>>>>> And also "horizontal lines are not proper" bug is fixed in the same >>>>>>>> which was reported by Dave in previous patch. >>>>>>>> >>>>>>>> Regards, >>>>>>>> Sanket Mehta >>>>>>>> Sr Software engineer >>>>>>>> Enterprisedb >>>>>>>> >>>>>>>> On Thu, Apr 21, 2016 at 8:38 PM, Sanket Mehta < >>>>>>>> [email protected]> wrote: >>>>>>>> >>>>>>>>> Hi Team, >>>>>>>>> >>>>>>>>> PFA the first patch for graphical explain integrated in sql editor. >>>>>>>>> >>>>>>>>> Below are the few things which are different from previous patch >>>>>>>>> which was sent for stand alone graphical explain. >>>>>>>>> >>>>>>>>> - Now user can select Explain/Explain Analyze with four optional >>>>>>>>> properties (Verbose, costs, timing and buffers) >>>>>>>>> >>>>>>>>> - Initially graph will be scale (according to only its width not >>>>>>>>> height) to fit to screen so no blank space will be there in case of very >>>>>>>>> large graph. >>>>>>>>> >>>>>>>>> - Along with zoom in/out button, "zoom to original" button is also >>>>>>>>> provided, by clicking on which graph will be scale to its original size >>>>>>>>> (not same as initial one which is according to screen size). >>>>>>>>> >>>>>>>>> Please do review this patch and let me know in case you have any >>>>>>>>> comments. >>>>>>>>> >>>>>>>>> >>>>>>>>> Regards, >>>>>>>>> Sanket Mehta >>>>>>>>> Sr Software engineer >>>>>>>>> Enterprisedb >>>>>>>>> >>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >>>> >>>> -- >>>> Sent via pgadmin-hackers mailing list ([email protected]) >>>> To make changes to your subscription: >>>> http://www.postgresql.org/mailpref/pgadmin-hackers >>>> >>>> >>> >>> >>> -- >>> *Akshay Joshi* >>> *Principal Software Engineer * >>> >>> >>> >>> *Phone: +91 20-3058-9517Mobile: +91 976-788-8246* >>> >> >> > ^ permalink raw reply [nested|flat] 10+ messages in thread
end of thread, other threads:[~2016-05-15 19:41 UTC | newest] Thread overview: 10+ messages (download: mbox mbox.gz follow: Atom feed) -- links below jump to the message on this page -- 2016-04-21 15:08 PATCH: Graphincal explain integrated in sql editor Sanket Mehta <[email protected]> 2016-04-25 09:36 ` Sanket Mehta <[email protected]> 2016-04-25 11:06 ` Ashesh Vashi <[email protected]> 2016-05-09 15:19 ` Sanket Mehta <[email protected]> 2016-05-09 18:26 ` Sanket Mehta <[email protected]> 2016-05-10 06:51 ` Sanket Mehta <[email protected]> 2016-05-10 09:24 ` Akshay Joshi <[email protected]> 2016-05-13 10:25 ` Sanket Mehta <[email protected]> 2016-05-13 10:31 ` Sanket Mehta <[email protected]> 2016-05-15 19:41 ` Ashesh Vashi <[email protected]>
This inbox is served by agora; see mirroring instructions for how to clone and mirror all data and code used for this inbox