From 61abca1ad6aeb5108be7f06e9590c702d4013e7a Mon Sep 17 00:00:00 2001 From: neon12345 <784389+neon12345@users.noreply.github.com> Date: Sat, 14 Jun 2025 07:47:53 +0200 Subject: [PATCH] add recovered v2 spec --- vowl_v2/data/88x31.png | Bin 0 -> 1283 bytes vowl_v2/data/d3.v3.min.js | 5 + vowl_v2/data/favicon.ico | Bin 0 -> 1406 bytes vowl_v2/data/pagestyle.css | 325 ++++++ vowl_v2/data/specBrowserWarning.js | 36 + vowl_v2/data/specVOWL.js | 59 + vowl_v2/data/vowl.css | 111 ++ vowl_v2/data/webVOWLGraph.js | 1749 ++++++++++++++++++++++++++++ vowl_v2/index.html | 1260 ++++++++++++++++++++ vowl_v2/index.orig | 1260 ++++++++++++++++++++ vowl_v2/js/data/foaf_spec.json | 127 ++ 11 files changed, 4932 insertions(+) create mode 100644 vowl_v2/data/88x31.png create mode 100644 vowl_v2/data/d3.v3.min.js create mode 100644 vowl_v2/data/favicon.ico create mode 100644 vowl_v2/data/pagestyle.css create mode 100644 vowl_v2/data/specBrowserWarning.js create mode 100644 vowl_v2/data/specVOWL.js create mode 100644 vowl_v2/data/vowl.css create mode 100644 vowl_v2/data/webVOWLGraph.js create mode 100644 vowl_v2/index.html create mode 100644 vowl_v2/index.orig create mode 100644 vowl_v2/js/data/foaf_spec.json diff --git a/vowl_v2/data/88x31.png b/vowl_v2/data/88x31.png new file mode 100644 index 0000000000000000000000000000000000000000..cf596085a4ba8e2efe2c5bf1094b7226e03aa127 GIT binary patch literal 1283 zcmYk*X;4#F6bJB^gjy1t$Y6l7SV9K_j7X^)ZXkq!qyomEg%*&s0VA@AKu6F30YR36 z7_lgbLWN-*V)7EQlN}Pm5)ufDg~FgBQ&1^&jg1R^eCwItz5jD(&ZjeTtI4s4(I__* z003xG6p;dD0(3m>5zu|y*=B(PM~kAw0KkQ<0KmKi0ROH*xeNfm1OmWQDgf-i2>>o< zuchcCp;G*^ z5B2vC>GgvUoenb4*Ei6oGxYTtdV3AMTD?ZIPOZ_Y)jE~BPo;wNDwXRLYPDLSRVcJ_ zg+?LQ$mN=z9yLTJQ$eIsr9`3-i{&Cwk5Jen5XuAsX?M4j-!0+uB|N^E#}k7*5eSO7 zppeTGfLtMmE8u|LAV+Zjem5HgK{mguwf)YWw%e_(t&L5M4L2KD*IBFvR(*Yab!~O| zdPjcG!qtCv6=y^>^)G^3c>LpRB>idrZgnseOaf zo2EbBo<4BkJguP41$hZ(|2aZMlEh&%57PJKO%;dbOMMsuZH~9CD2qnRd;bFVr31zm zObZyxPIK)UNj>w7`bUU-$?eTMr`*ge+AC5jqO90lMPt&J7Z?%K#H}U7^NAH+R(eUG zLh6{PzLnc`FWSFTsD+uU!g+z!!-=Hhhz@IZqDg^DYmSs43W*q*$-=nO_ z1i!kI1O_#+V5yb!GnJ7=rDX4!mX{`{T&!0)d0)~>I@2c^;asuJr>?{8oU1ST)@KiN z#-xN8SuqLeO0aK>CXx`(oeS|Bqp&h$yIra)d+DtmfweffVLN3&DcjKCLE&gk)=c=- z+VWl3tn!sBFPa{Hpkyk)N+Kq2z}9fIcYjlr&mM8>^ft~u;Cb*Pc~IK|4!ZAV<1#S)HBeKthE2N|;1ZJ3VQgS5Qbl8lgSTUOi>>E4gC z4{)uWr@~pMTr3%{JtrGGUyFssyjQ{Ui>=753G%$3@zT*$f=#=3u_-UKOW^gLDCUz@ zz)c6}Np$6yd&7=@D#b02Wz?3N2h6v)c-tJ?i#N>MskJ&!yuh1Ybe;++e){var u=sa[e]+t;if(u in n)return u}}function g(){}function p(){}function v(n){function t(){for(var t,r=e,u=-1,i=r.length;++ue;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function D(n){return fa(n,ya),n}function P(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t0&&(n=n.substring(0,a));var s=Ma.get(n);return s&&(n=s,c=F),a?t?u:r:t?g:i}function H(n,t){return function(e){var r=Xo.event;Xo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Xo.event=r}}}function F(n,t){var e=H(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function O(){var n=".dragsuppress-"+ ++ba,t="click"+n,e=Xo.select(Go).on("touchmove"+n,d).on("dragstart"+n,d).on("selectstart"+n,d);if(_a){var r=Jo.style,u=r[_a];r[_a]="none"}return function(i){function o(){e.on(t,null)}e.on(n,null),_a&&(r[_a]=u),i&&(e.on(t,function(){d(),o()},!0),setTimeout(o,0))}}function Y(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>wa&&(Go.scrollX||Go.scrollY)){e=Xo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();wa=!(u.f||u.e),e.remove()}return wa?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function I(n){return n>0?1:0>n?-1:0}function Z(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function V(n){return n>1?0:-1>n?Sa:Math.acos(n)}function X(n){return n>1?Ea:-1>n?-Ea:Math.asin(n)}function $(n){return((n=Math.exp(n))-1/n)/2}function B(n){return((n=Math.exp(n))+1/n)/2}function W(n){return((n=Math.exp(2*n))-1)/(n+1)}function J(n){return(n=Math.sin(n/2))*n}function G(){}function K(n,t,e){return new Q(n,t,e)}function Q(n,t,e){this.h=n,this.s=t,this.l=e}function nt(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,gt(u(n+120),u(n),u(n-120))}function tt(n,t,e){return new et(n,t,e)}function et(n,t,e){this.h=n,this.c=t,this.l=e}function rt(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),ut(e,Math.cos(n*=Na)*t,Math.sin(n)*t)}function ut(n,t,e){return new it(n,t,e)}function it(n,t,e){this.l=n,this.a=t,this.b=e}function ot(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=ct(u)*Fa,r=ct(r)*Oa,i=ct(i)*Ya,gt(lt(3.2404542*u-1.5371385*r-.4985314*i),lt(-.969266*u+1.8760108*r+.041556*i),lt(.0556434*u-.2040259*r+1.0572252*i))}function at(n,t,e){return n>0?tt(Math.atan2(e,t)*La,Math.sqrt(t*t+e*e),n):tt(0/0,0/0,n)}function ct(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function st(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function lt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function ft(n){return gt(n>>16,255&n>>8,255&n)}function ht(n){return ft(n)+""}function gt(n,t,e){return new pt(n,t,e)}function pt(n,t,e){this.r=n,this.g=t,this.b=e}function vt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function dt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(Mt(u[0]),Mt(u[1]),Mt(u[2]))}return(i=Va.get(n))?t(i.r,i.g,i.b):(null!=n&&"#"===n.charAt(0)&&(4===n.length?(o=n.charAt(1),o+=o,a=n.charAt(2),a+=a,c=n.charAt(3),c+=c):7===n.length&&(o=n.substring(1,3),a=n.substring(3,5),c=n.substring(5,7)),o=parseInt(o,16),a=parseInt(a,16),c=parseInt(c,16)),t(o,a,c))}function mt(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),K(r,u,c)}function yt(n,t,e){n=xt(n),t=xt(t),e=xt(e);var r=st((.4124564*n+.3575761*t+.1804375*e)/Fa),u=st((.2126729*n+.7151522*t+.072175*e)/Oa),i=st((.0193339*n+.119192*t+.9503041*e)/Ya);return ut(116*u-16,500*(r-u),200*(u-i))}function xt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function Mt(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function _t(n){return"function"==typeof n?n:function(){return n}}function bt(n){return n}function wt(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),St(t,e,n,r)}}function St(n,t,e,r){function u(){var n,t=c.status;if(!t&&c.responseText||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=Xo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,s=null;return!Go.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=Xo.event;Xo.event=n;try{o.progress.call(i,c)}finally{Xo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(s=n,i):s},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Bo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var l in a)c.setRequestHeader(l,a[l]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=s&&(c.responseType=s),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},Xo.rebind(i,o,"on"),null==r?i:i.get(kt(r))}function kt(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function Et(){var n=At(),t=Ct()-n;t>24?(isFinite(t)&&(clearTimeout(Wa),Wa=setTimeout(Et,t)),Ba=0):(Ba=1,Ga(Et))}function At(){var n=Date.now();for(Ja=Xa;Ja;)n>=Ja.t&&(Ja.f=Ja.c(n-Ja.t)),Ja=Ja.n;return n}function Ct(){for(var n,t=Xa,e=1/0;t;)t.f?t=n?n.n=t.n:Xa=t.n:(t.t8?function(n){return n/e}:function(n){return n*e},symbol:n}}function zt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r?function(n){for(var t=n.length,u=[],i=0,o=r[0];t>0&&o>0;)u.push(n.substring(t-=o,t+o)),o=r[i=(i+1)%r.length];return u.reverse().join(e)}:bt;return function(n){var e=Qa.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"",c=e[4]||"",s=e[5],l=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1;switch(h&&(h=+h.substring(1)),(s||"0"===r&&"="===o)&&(s=r="0",o="=",f&&(l-=Math.floor((l-1)/4))),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=nc.get(g)||qt;var y=s&&f;return function(n){if(m&&n%1)return"";var e=0>n||0===n&&0>1/n?(n=-n,"-"):a;if(0>p){var u=Xo.formatPrefix(n,h);n=u.scale(n),d=u.symbol}else n*=p;n=g(n,h);var c=n.lastIndexOf("."),x=0>c?n:n.substring(0,c),M=0>c?"":t+n.substring(c+1);!s&&f&&(x=i(x));var _=v.length+x.length+M.length+(y?0:e.length),b=l>_?new Array(_=l-_+1).join(r):"";return y&&(x=i(b+x)),e+=v,n=x+M,("<"===o?e+n+b:">"===o?b+e+n:"^"===o?b.substring(0,_>>=1)+e+n+b.substring(_):e+(y?n:b+n))+d}}}function qt(n){return n+""}function Tt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Rt(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new ec(e-1)),1),e}function i(n,e){return t(n=new ec(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{ec=Tt;var r=new Tt;return r._=n,o(r,t,e)}finally{ec=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Dt(n);return c.floor=c,c.round=Dt(r),c.ceil=Dt(u),c.offset=Dt(i),c.range=a,n}function Dt(n){return function(t,e){try{ec=Tt;var r=new Tt;return r._=t,n(r,e)._}finally{ec=Date}}}function Pt(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++aa;){if(r>=s)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=N[o in uc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){b.lastIndex=0;var r=b.exec(t.substring(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){M.lastIndex=0;var r=M.exec(t.substring(e));return r?(n.w=_.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.substring(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.substring(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,C.c.toString(),t,r)}function c(n,t,r){return e(n,C.x.toString(),t,r)}function s(n,t,r){return e(n,C.X.toString(),t,r)}function l(n,t,e){var r=x.get(t.substring(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{ec=Tt;var t=new ec;return t._=n,r(t)}finally{ec=Date}}var r=t(n);return e.parse=function(n){try{ec=Tt;var t=r.parse(n);return t&&t._}finally{ec=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ee;var x=Xo.map(),M=jt(v),_=Ht(v),b=jt(d),w=Ht(d),S=jt(m),k=Ht(m),E=jt(y),A=Ht(y);p.forEach(function(n,t){x.set(n.toLowerCase(),t)});var C={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return Ut(n.getDate(),t,2)},e:function(n,t){return Ut(n.getDate(),t,2)},H:function(n,t){return Ut(n.getHours(),t,2)},I:function(n,t){return Ut(n.getHours()%12||12,t,2)},j:function(n,t){return Ut(1+tc.dayOfYear(n),t,3)},L:function(n,t){return Ut(n.getMilliseconds(),t,3)},m:function(n,t){return Ut(n.getMonth()+1,t,2)},M:function(n,t){return Ut(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return Ut(n.getSeconds(),t,2)},U:function(n,t){return Ut(tc.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Ut(tc.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return Ut(n.getFullYear()%100,t,2)},Y:function(n,t){return Ut(n.getFullYear()%1e4,t,4)},Z:ne,"%":function(){return"%"}},N={a:r,A:u,b:i,B:o,c:a,d:Bt,e:Bt,H:Jt,I:Jt,j:Wt,L:Qt,m:$t,M:Gt,p:l,S:Kt,U:Ot,w:Ft,W:Yt,x:c,X:s,y:Zt,Y:It,Z:Vt,"%":te};return t}function Ut(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function jt(n){return new RegExp("^(?:"+n.map(Xo.requote).join("|")+")","i")}function Ht(n){for(var t=new u,e=-1,r=n.length;++e68?1900:2e3)}function $t(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Bt(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function Wt(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function Jt(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function Gt(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function Kt(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function Qt(n,t,e){ic.lastIndex=0;var r=ic.exec(t.substring(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ne(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=~~(oa(t)/60),u=oa(t)%60;return e+Ut(r,"0",2)+Ut(u,"0",2)}function te(n,t,e){oc.lastIndex=0;var r=oc.exec(t.substring(e,e+1));return r?e+r[0].length:-1}function ee(n){for(var t=n.length,e=-1;++ea;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c=new ke(e,n,null,!0),s=new ke(e,null,c,!1);c.o=s,i.push(c),o.push(s),c=new ke(r,n,null,!1),s=new ke(r,null,c,!0),c.o=s,i.push(c),o.push(s)}}),o.sort(t),Se(i),Se(o),i.length){for(var a=0,c=e,s=o.length;s>a;++a)o[a].e=c=!c;for(var l,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;l=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,s=l.length;s>a;++a)u.point((f=l[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){l=g.p.z;for(var a=l.length-1;a>=0;--a)u.point((f=l[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,l=g.z,p=!p}while(!g.v);u.lineEnd()}}}function Se(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Ae))}}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:s,polygonStart:function(){y.point=l,y.lineStart=f,y.lineEnd=h,g=[],p=[],i.polygonStart()},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=s,g=Xo.merge(g);var n=Le(m,p);g.length?we(g,Ne,n,e,i):n&&(i.lineStart(),e(null,null,1,i),i.lineEnd()),i.polygonEnd(),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=Ce(),M=t(x);return y}}function Ae(n){return n.length>1}function Ce(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:g,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Ne(n,t){return((n=n.x)[0]<0?n[1]-Ea-Aa:Ea-n[1])-((t=t.x)[0]<0?t[1]-Ea-Aa:Ea-t[1])}function Le(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;hc.reset();for(var a=0,c=t.length;c>a;++a){var s=t[a],l=s.length;if(l)for(var f=s[0],h=f[0],g=f[1]/2+Sa/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===l&&(d=0),n=s[d];var m=n[0],y=n[1]/2+Sa/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=oa(_)>Sa,w=p*x;if(hc.add(Math.atan2(w*Math.sin(_),v*M+w*Math.cos(_))),i+=b?_+(_>=0?ka:-ka):_,b^h>=e^m>=e){var S=fe(se(f),se(n));pe(S);var k=fe(u,S);pe(k);var E=(b^_>=0?-1:1)*X(k[2]);(r>E||r===E&&(S[0]||S[1]))&&(o+=b^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-Aa>i||Aa>i&&0>hc)^1&o}function ze(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?Sa:-Sa,c=oa(i-e);oa(c-Sa)0?Ea:-Ea),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=Sa&&(oa(e-u)Aa?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function Te(n,t,e,r){var u;if(null==n)u=e*Ea,r.point(-Sa,u),r.point(0,u),r.point(Sa,u),r.point(Sa,0),r.point(Sa,-u),r.point(0,-u),r.point(-Sa,-u),r.point(-Sa,0),r.point(-Sa,u);else if(oa(n[0]-t[0])>Aa){var i=n[0]i}function e(n){var e,i,c,s,l;return{lineStart:function(){s=c=!1,l=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?Sa:-Sa),h):0;if(!e&&(s=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(de(e,g)||de(p,g))&&(p[0]+=Aa,p[1]+=Aa,v=t(p[0],p[1]))),v!==c)l=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(l=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&de(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return l|(s&&c)<<1}}}function r(n,t,e){var r=se(n),u=se(t),o=[1,0,0],a=fe(r,u),c=le(a,a),s=a[0],l=c-s*s;if(!l)return!e&&n;var f=i*c/l,h=-i*s/l,g=fe(o,a),p=ge(o,f),v=ge(a,h);he(p,v);var d=g,m=le(p,d),y=le(d,d),x=m*m-y*(le(p,p)-1);if(!(0>x)){var M=Math.sqrt(x),_=ge(d,(-m-M)/y);if(he(_,p),_=ve(_),!e)return _;var b,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(b=w,w=S,S=b);var A=S-w,C=oa(A-Sa)A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(oa(_[0]-w)Sa^(w<=_[0]&&_[0]<=S)){var L=ge(d,(-m+M)/y);return he(L,p),[_,ve(L)]}}}function u(t,e){var r=o?n:Sa-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=oa(i)>Aa,c=cr(n,6*Na);return Ee(t,e,c,o?[0,-n]:[-Sa,n-Sa])}function De(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,s=o.y,l=a.x,f=a.y,h=0,g=1,p=l-c,v=f-s;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-s,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-s,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:s+h*v}),1>g&&(u.b={x:c+g*p,y:s+g*v}),u}}}}}}function Pe(n,t,e,r){function u(r,u){return oa(r[0]-n)0?0:3:oa(r[0]-e)0?2:1:oa(r[1]-t)0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,s=a[0];c>o;++o)i=a[o],s[1]<=r?i[1]>r&&Z(s,i,n)>0&&++t:i[1]<=r&&Z(s,i,n)<0&&--t,s=i;return 0!==t}function s(i,a,c,s){var l=0,f=0;if(null==i||(l=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do s.point(0===l||3===l?n:e,l>1?r:t);while((l=(l+c+4)%4)!==f)}else s.point(a[0],a[1])}function l(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){l(n,t)&&a.point(n,t)}function h(){N.point=p,d&&d.push(m=[]),S=!0,w=!1,_=b=0/0}function g(){v&&(p(y,x),M&&w&&A.rejoin(),v.push(A.buffer())),N.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Ac,Math.min(Ac,n)),t=Math.max(-Ac,Math.min(Ac,t));var e=l(n,t);if(d&&m.push([n,t]),S)y=n,x=t,M=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:_,y:b},b:{x:n,y:t}};C(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}_=n,b=t,w=e}var v,d,m,y,x,M,_,b,w,S,k,E=a,A=Ce(),C=De(n,t,e,r),N={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=Xo.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),s(null,null,1,a),a.lineEnd()),u&&we(v,i,t,s,a),a.polygonEnd()),v=d=m=null}};return N}}function Ue(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function je(n){var t=0,e=Sa/3,r=nr(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*Sa/180,e=n[1]*Sa/180):[180*(t/Sa),180*(e/Sa)]},u}function He(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,X((i-(n*n+e*e)*u*u)/(2*u))]},e}function Fe(){function n(n,t){Nc+=u*n-r*t,r=n,u=t}var t,e,r,u;Rc.point=function(i,o){Rc.point=n,t=r=i,e=u=o},Rc.lineEnd=function(){n(t,e)}}function Oe(n,t){Lc>n&&(Lc=n),n>qc&&(qc=n),zc>t&&(zc=t),t>Tc&&(Tc=t)}function Ye(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Ie(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Ie(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Ie(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function Ze(n,t){dc+=n,mc+=t,++yc}function Ve(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);xc+=o*(t+n)/2,Mc+=o*(e+r)/2,_c+=o,Ze(t=n,e=r)}var t,e;Pc.point=function(r,u){Pc.point=n,Ze(t=r,e=u)}}function Xe(){Pc.point=Ze}function $e(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);xc+=o*(r+n)/2,Mc+=o*(u+t)/2,_c+=o,o=u*n-r*t,bc+=o*(r+n),wc+=o*(u+t),Sc+=3*o,Ze(r=n,u=t)}var t,e,r,u;Pc.point=function(i,o){Pc.point=n,Ze(t=r=i,e=u=o)},Pc.lineEnd=function(){n(t,e)}}function Be(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,ka)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:g};return a}function We(n){function t(n){return(a?r:e)(n)}function e(t){return Ke(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){x=0/0,S.point=i,t.lineStart()}function i(e,r){var i=se([e,r]),o=n(e,r);u(x,M,y,_,b,w,x=o[0],M=o[1],y=e,_=i[0],b=i[1],w=i[2],a,t),t.point(x,M)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=s,S.lineEnd=l}function s(n,t){i(f=n,h=t),g=x,p=M,v=_,d=b,m=w,S.point=i}function l(){u(x,M,y,_,b,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,x,M,_,b,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,s,l,f,h,g,p,v,d,m){var y=l-t,x=f-e,M=y*y+x*x;if(M>4*i&&d--){var _=a+g,b=c+p,w=s+v,S=Math.sqrt(_*_+b*b+w*w),k=Math.asin(w/=S),E=oa(oa(w)-1)i||oa((y*L+x*z)/M-.5)>.3||o>a*g+c*p+s*v)&&(u(t,e,r,a,c,s,C,N,E,_/=S,b/=S,w,d,m),m.point(C,N),u(C,N,E,_,b,w,l,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*Na),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function Je(n){var t=We(function(t,e){return n([t*La,e*La])});return function(n){return tr(t(n))}}function Ge(n){this.stream=n}function Ke(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function Qe(n){return nr(function(){return n})()}function nr(n){function t(n){return n=a(n[0]*Na,n[1]*Na),[n[0]*h+c,s-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(s-n[1])/h),n&&[n[0]*La,n[1]*La]}function r(){a=Ue(o=ur(m,y,x),i);var n=i(v,d);return c=g-n[0]*h,s=p+n[1]*h,u()}function u(){return l&&(l.valid=!1,l=null),t}var i,o,a,c,s,l,f=We(function(n,t){return n=i(n,t),[n[0]*h+c,s-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,y=0,x=0,M=Ec,_=bt,b=null,w=null;return t.stream=function(n){return l&&(l.valid=!1),l=tr(M(o,f(_(n)))),l.valid=!0,l},t.clipAngle=function(n){return arguments.length?(M=null==n?(b=n,Ec):Re((b=+n)*Na),u()):b +},t.clipExtent=function(n){return arguments.length?(w=n,_=n?Pe(n[0][0],n[0][1],n[1][0],n[1][1]):bt,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*Na,d=n[1]%360*Na,r()):[v*La,d*La]},t.rotate=function(n){return arguments.length?(m=n[0]%360*Na,y=n[1]%360*Na,x=n.length>2?n[2]%360*Na:0,r()):[m*La,y*La,x*La]},Xo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function tr(n){return Ke(n,function(t,e){n.point(t*Na,e*Na)})}function er(n,t){return[n,t]}function rr(n,t){return[n>Sa?n-ka:-Sa>n?n+ka:n,t]}function ur(n,t,e){return n?t||e?Ue(or(n),ar(t,e)):or(n):t||e?ar(t,e):rr}function ir(n){return function(t,e){return t+=n,[t>Sa?t-ka:-Sa>t?t+ka:t,e]}}function or(n){var t=ir(n);return t.invert=ir(-n),t}function ar(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*r+a*u;return[Math.atan2(c*i-l*o,a*r-s*u),X(l*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,s=Math.sin(t),l=s*i-c*o;return[Math.atan2(c*i+s*o,a*r+l*u),X(l*r-a*u)]},e}function cr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=sr(e,u),i=sr(e,i),(o>0?i>u:u>i)&&(u+=o*ka)):(u=n+o*ka,i=n-.5*c);for(var s,l=u;o>0?l>i:i>l;l-=c)a.point((s=ve([e,-r*Math.cos(l),-r*Math.sin(l)]))[0],s[1])}}function sr(n,t){var e=se(t);e[0]-=n,pe(e);var r=V(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Aa)%(2*Math.PI)}function lr(n,t,e){var r=Xo.range(n,t-Aa,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function fr(n,t,e){var r=Xo.range(n,t-Aa,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function hr(n){return n.source}function gr(n){return n.target}function pr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),s=u*Math.sin(n),l=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(J(r-t)+u*o*J(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*l,u=e*s+t*f,o=e*i+t*a;return[Math.atan2(u,r)*La,Math.atan2(o,Math.sqrt(r*r+u*u))*La]}:function(){return[n*La,t*La]};return p.distance=h,p}function vr(){function n(n,u){var i=Math.sin(u*=Na),o=Math.cos(u),a=oa((n*=Na)-t),c=Math.cos(a);Uc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;jc.point=function(u,i){t=u*Na,e=Math.sin(i*=Na),r=Math.cos(i),jc.point=n},jc.lineEnd=function(){jc.point=jc.lineEnd=g}}function dr(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function mr(n,t){function e(n,t){var e=oa(oa(t)-Ea)u;u++){for(;r>1&&Z(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function kr(n,t){return n[0]-t[0]||n[1]-t[1]}function Er(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Ar(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],s=e[1],l=t[1]-c,f=r[1]-s,h=(a*(c-s)-f*(u-i))/(f*o-a*l);return[u+h*o,c+h*l]}function Cr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Nr(){Jr(this),this.edge=this.site=this.circle=null}function Lr(n){var t=Jc.pop()||new Nr;return t.site=n,t}function zr(n){Or(n),$c.remove(n),Jc.push(n),Jr(n)}function qr(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];zr(n);for(var c=i;c.circle&&oa(e-c.circle.x)l;++l)s=a[l],c=a[l-1],$r(s.edge,c.site,s.site,u);c=a[0],s=a[f-1],s.edge=Vr(c.site,s.site,null,u),Fr(c),Fr(s)}function Tr(n){for(var t,e,r,u,i=n.x,o=n.y,a=$c._;a;)if(r=Rr(a,o)-i,r>Aa)a=a.L;else{if(u=i-Dr(a,o),!(u>Aa)){r>-Aa?(t=a.P,e=a):u>-Aa?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Lr(n);if($c.insert(t,c),t||e){if(t===e)return Or(t),e=Lr(t.site),$c.insert(c,e),c.edge=e.edge=Vr(t.site,c.site),Fr(t),Fr(e),void 0;if(!e)return c.edge=Vr(t.site,c.site),void 0;Or(t),Or(e);var s=t.site,l=s.x,f=s.y,h=n.x-l,g=n.y-f,p=e.site,v=p.x-l,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,x=v*v+d*d,M={x:(d*y-g*x)/m+l,y:(h*x-v*y)/m+f};$r(e.edge,s,p,M),c.edge=Vr(s,n,null,M),e.edge=Vr(n,p,null,M),Fr(t),Fr(e)}}function Rr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,s=c-t;if(!s)return a;var l=a-r,f=1/i-1/s,h=l/s;return f?(-h+Math.sqrt(h*h-2*f*(l*l/(-2*s)-c+s/2+u-i/2)))/f+r:(r+a)/2}function Dr(n,t){var e=n.N;if(e)return Rr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Pr(n){this.site=n,this.edges=[]}function Ur(n){for(var t,e,r,u,i,o,a,c,s,l,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Xc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)l=a[o].end(),r=l.x,u=l.y,s=a[++o%c].start(),t=s.x,e=s.y,(oa(r-t)>Aa||oa(u-e)>Aa)&&(a.splice(o,0,new Br(Xr(i.site,l,oa(r-f)Aa?{x:f,y:oa(t-f)Aa?{x:oa(e-p)Aa?{x:h,y:oa(t-h)Aa?{x:oa(e-g)=-Ca)){var g=c*c+s*s,p=l*l+f*f,v=(f*g-s*p)/h,d=(c*p-l*g)/h,f=d+a,m=Gc.pop()||new Hr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,x=Wc._;x;)if(m.yd||d>=a)return;if(h>p){if(i){if(i.y>=s)return}else i={x:d,y:c};e={x:d,y:s}}else{if(i){if(i.yr||r>1)if(h>p){if(i){if(i.y>=s)return}else i={x:(c-u)/r,y:c};e={x:(s-u)/r,y:s}}else{if(i){if(i.yg){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.xr;++r)if(o=l[r],o.x==e[0]){if(o.i)if(null==s[o.i+1])for(s[o.i-1]+=o.x,s.splice(o.i,1),u=r+1;i>u;++u)l[u].i--;else for(s[o.i-1]+=o.x+s[o.i+1],s.splice(o.i,2),u=r+1;i>u;++u)l[u].i-=2;else if(null==s[o.i+1])s[o.i]=o.x;else for(s[o.i]=o.x+s[o.i+1],s.splice(o.i+1,1),u=r+1;i>u;++u)l[u].i--;l.splice(r,1),i--,r--}else o.x=su(parseFloat(e[0]),parseFloat(o.x));for(;i>r;)o=l.pop(),null==s[o.i+1]?s[o.i]=o.x:(s[o.i]=o.x+s[o.i+1],s.splice(o.i+1,1)),i--;return 1===s.length?null==s[0]?(o=l[0].x,function(n){return o(n)+""}):function(){return t}:function(n){for(r=0;i>r;++r)s[(o=l[r]).i]=o.x(n);return s.join("")}}function fu(n,t){for(var e,r=Xo.interpolators.length;--r>=0&&!(e=Xo.interpolators[r](n,t)););return e}function hu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(fu(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function gu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function pu(n){return function(t){return 1-n(1-t)}}function vu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function du(n){return n*n}function mu(n){return n*n*n}function yu(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function xu(n){return function(t){return Math.pow(t,n)}}function Mu(n){return 1-Math.cos(n*Ea)}function _u(n){return Math.pow(2,10*(n-1))}function bu(n){return 1-Math.sqrt(1-n*n)}function wu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/ka*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*ka/t)}}function Su(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function ku(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Eu(n,t){n=Xo.hcl(n),t=Xo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return rt(e+i*n,r+o*n,u+a*n)+""}}function Au(n,t){n=Xo.hsl(n),t=Xo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return nt(e+i*n,r+o*n,u+a*n)+""}}function Cu(n,t){n=Xo.lab(n),t=Xo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ot(e+i*n,r+o*n,u+a*n)+""}}function Nu(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Lu(n){var t=[n.a,n.b],e=[n.c,n.d],r=qu(t),u=zu(t,e),i=qu(Tu(e,t,-u))||0;t[0]*e[1]180?l+=360:l-s>180&&(s+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:su(s,l)})):l&&r.push(r.pop()+"rotate("+l+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:su(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:su(g[0],p[0])},{i:e-2,x:su(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++ie;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function ei(n){return n.reduce(ri,0)}function ri(n,t){return n+t[1]}function ui(n,t){return ii(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function ii(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function oi(n){return[Xo.min(n),Xo.max(n)]}function ai(n,t){return n.parent==t.parent?1:2}function ci(n){var t=n.children;return t&&t.length?t[0]:n._tree.thread}function si(n){var t,e=n.children;return e&&(t=e.length)?e[t-1]:n._tree.thread}function li(n,t){var e=n.children;if(e&&(u=e.length))for(var r,u,i=-1;++i0&&(n=r);return n}function fi(n,t){return n.x-t.x}function hi(n,t){return t.x-n.x}function gi(n,t){return n.depth-t.depth}function pi(n,t){function e(n,r){var u=n.children;if(u&&(o=u.length))for(var i,o,a=null,c=-1;++c=0;)t=u[i]._tree,t.prelim+=e,t.mod+=e,e+=t.shift+(r+=t.change)}function di(n,t,e){n=n._tree,t=t._tree;var r=e/(t.number-n.number);n.change+=r,t.change-=r,t.shift+=e,t.prelim+=e,t.mod+=e}function mi(n,t,e){return n._tree.ancestor.parent==t.parent?n._tree.ancestor:e}function yi(n,t){return n.value-t.value}function xi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function Mi(n,t){n._pack_next=t,t._pack_prev=n}function _i(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function bi(n){function t(n){l=Math.min(n.x-n.r,l),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(s=e.length)){var e,r,u,i,o,a,c,s,l=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(wi),r=e[0],r.x=-r.r,r.y=0,t(r),s>1&&(u=e[1],u.x=u.r,u.y=0,t(u),s>2))for(i=e[2],Ei(r,u,i),t(i),xi(r,i),r._pack_prev=i,xi(i,u),u=r._pack_next,o=3;s>o;o++){Ei(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(_i(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!_i(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.ro;o++)i=e[o],i.x-=m,i.y-=y,x=Math.max(x,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=x,e.forEach(Si)}}function wi(n){n._pack_next=n._pack_prev=n}function Si(n){delete n._pack_next,delete n._pack_prev}function ki(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++iu&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Ti(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Ri(n){return n.rangeExtent?n.rangeExtent():Ti(n.range())}function Di(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function Pi(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Ui(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:ls}function ji(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]2?ji:Di,c=r?Pu:Du;return o=u(n,t,c,e),a=u(t,n,c,fu),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Nu)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Ii(n,t)},i.tickFormat=function(t,e){return Zi(n,t,e)},i.nice=function(t){return Oi(n,t),u()},i.copy=function(){return Hi(n,t,e,r)},u()}function Fi(n,t){return Xo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Oi(n,t){return Pi(n,Ui(Yi(n,t)[2]))}function Yi(n,t){null==t&&(t=10);var e=Ti(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Ii(n,t){return Xo.range.apply(Xo,Yi(n,t))}function Zi(n,t,e){var r=Yi(n,t);return Xo.format(e?e.replace(Qa,function(n,t,e,u,i,o,a,c,s,l){return[t,e,u,i,o,a,c,s||"."+Xi(l,r),l].join("")}):",."+Vi(r[2])+"f")}function Vi(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Xi(n,t){var e=Vi(t[2]);return n in fs?Math.abs(e-Vi(Math.max(Math.abs(t[0]),Math.abs(t[1]))))+ +("e"!==n):e-2*("%"===n)}function $i(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=Pi(r.map(u),e?Math:gs);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Ti(r),o=[],a=n[0],c=n[1],s=Math.floor(u(a)),l=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(l-s)){if(e){for(;l>s;s++)for(var h=1;f>h;h++)o.push(i(s)*h);o.push(i(s))}else for(o.push(i(s));s++0;h--)o.push(i(s)*h);for(s=0;o[s]c;l--);o=o.slice(s,l)}return o},o.tickFormat=function(n,t){if(!arguments.length)return hs;arguments.length<2?t=hs:"function"!=typeof t&&(t=Xo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return $i(n.copy(),t,e,r)},Fi(o,n)}function Bi(n,t,e){function r(t){return n(u(t))}var u=Wi(t),i=Wi(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Ii(e,n)},r.tickFormat=function(n,t){return Zi(e,n,t)},r.nice=function(n){return r.domain(Oi(e,n))},r.exponent=function(o){return arguments.length?(u=Wi(t=o),i=Wi(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Bi(n.copy(),t,e)},Fi(r,n)}function Wi(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Ji(n,t){function e(e){return o[((i.get(e)||"range"===t.t&&i.set(e,n.push(e)))-1)%o.length]}function r(t,e){return Xo.range(n.length).map(function(n){return t+e*n})}var i,o,a;return e.domain=function(r){if(!arguments.length)return n;n=[],i=new u;for(var o,a=-1,c=r.length;++ae?[0/0,0/0]:[e>0?u[e-1]:n[0],et?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return Ki(n,t,e)},u()}function Qi(n,t){function e(e){return e>=e?t[Xo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return Qi(n,t)},e}function no(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Ii(n,t)},t.tickFormat=function(t,e){return Zi(n,t,e)},t.copy=function(){return no(n)},t}function to(n){return n.innerRadius}function eo(n){return n.outerRadius}function ro(n){return n.startAngle}function uo(n){return n.endAngle}function io(n){function t(t){function o(){s.push("M",i(n(l),a))}for(var c,s=[],l=[],f=-1,h=t.length,g=_t(e),p=_t(r);++f1&&u.push("H",r[0]),u.join("")}function so(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var s=2;s9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function Eo(n){return n.length<3?oo(n):n[0]+po(n,ko(n))}function Ao(n){for(var t,e,r,u=-1,i=n.length;++ue?s():(i.active=e,o.event&&o.event.start.call(n,l,t),o.tween.forEach(function(e,r){(r=r.call(n,l,t))&&v.push(r)}),Xo.timer(function(){return p.c=c(r||1)?be:c,1},0,a),void 0)}function c(r){if(i.active!==e)return s();for(var u=r/g,a=f(u),c=v.length;c>0;)v[--c].call(n,a);return u>=1?(o.event&&o.event.end.call(n,l,t),s()):void 0}function s(){return--i.count?delete i[e]:delete n.__transition__,1}var l=n.__data__,f=o.ease,h=o.delay,g=o.duration,p=Ja,v=[];return p.t=h+a,r>=h?u(r-h):(p.c=u,void 0)},0,a)}}function Ho(n,t){n.attr("transform",function(n){return"translate("+t(n)+",0)"})}function Fo(n,t){n.attr("transform",function(n){return"translate(0,"+t(n)+")"})}function Oo(n){return n.toISOString()}function Yo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=Xo.bisect(js,u);return i==js.length?[t.year,Yi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/js[i-1]1?{floor:function(t){for(;e(t=n.floor(t));)t=Io(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Io(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Ti(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Io(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Yo(n.copy(),t,e)},Fi(r,n)}function Io(n){return new Date(n)}function Zo(n){return JSON.parse(n.responseText)}function Vo(n){var t=Wo.createRange();return t.selectNode(Wo.body),t.createContextualFragment(n.responseText)}var Xo={version:"3.4.1"};Date.now||(Date.now=function(){return+new Date});var $o=[].slice,Bo=function(n){return $o.call(n)},Wo=document,Jo=Wo.documentElement,Go=window;try{Bo(Jo.childNodes)[0].nodeType}catch(Ko){Bo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{Wo.createElement("div").style.setProperty("opacity",0,"")}catch(Qo){var na=Go.Element.prototype,ta=na.setAttribute,ea=na.setAttributeNS,ra=Go.CSSStyleDeclaration.prototype,ua=ra.setProperty;na.setAttribute=function(n,t){ta.call(this,n,t+"")},na.setAttributeNS=function(n,t,e){ea.call(this,n,t,e+"")},ra.setProperty=function(n,t,e){ua.call(this,n,t+"",e)}}Xo.ascending=function(n,t){return t>n?-1:n>t?1:n>=t?0:0/0},Xo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},Xo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=e);)e=void 0;for(;++ur&&(e=r)}else{for(;++u=e);)e=void 0;for(;++ur&&(e=r)}return e},Xo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u=e);)e=void 0;for(;++ue&&(e=r)}else{for(;++u=e);)e=void 0;for(;++ue&&(e=r)}return e},Xo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i=e);)e=u=void 0;for(;++ir&&(e=r),r>u&&(u=r))}else{for(;++i=e);)e=void 0;for(;++ir&&(e=r),r>u&&(u=r))}return[e,u]},Xo.sum=function(n,t){var e,r=0,u=n.length,i=-1;if(1===arguments.length)for(;++i1&&(t=t.map(e)),t=t.filter(n),t.length?Xo.quantile(t.sort(Xo.ascending),.5):void 0},Xo.bisector=function(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n.call(t,t[i],i)r;){var i=r+u>>>1;er?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},Xo.zip=function(){if(!(u=arguments.length))return[];for(var n=-1,e=Xo.min(arguments,t),r=new Array(e);++n=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var oa=Math.abs;Xo.range=function(n,t,r){if(arguments.length<3&&(r=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/r)throw new Error("infinite range");var u,i=[],o=e(oa(r)),a=-1;if(n*=o,t*=o,r*=o,0>r)for(;(u=n+r*++a)>t;)i.push(u/o);else for(;(u=n+r*++a)=o.length)return r?r.call(i,a):e?a.sort(e):a;for(var s,l,f,h,g=-1,p=a.length,v=o[c++],d=new u;++g=o.length)return n;var r=[],u=a[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,i={},o=[],a=[];return i.map=function(t,e){return n(e,t,0)},i.entries=function(e){return t(n(Xo.map,e,0),0)},i.key=function(n){return o.push(n),i},i.sortKeys=function(n){return a[o.length-1]=n,i},i.sortValues=function(n){return e=n,i},i.rollup=function(n){return r=n,i},i},Xo.set=function(n){var t=new l;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},r(l,{has:i,add:function(n){return this[aa+n]=!0,n},remove:function(n){return n=aa+n,n in this&&delete this[n]},values:a,size:c,empty:s,forEach:function(n){for(var t in this)t.charCodeAt(0)===ca&&n.call(this,t.substring(1))}}),Xo.behavior={},Xo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r=0&&(r=n.substring(e+1),n=n.substring(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Xo.event=null,Xo.requote=function(n){return n.replace(la,"\\$&")};var la=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,fa={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},ha=function(n,t){return t.querySelector(n)},ga=function(n,t){return t.querySelectorAll(n)},pa=Jo[h(Jo,"matchesSelector")],va=function(n,t){return pa.call(n,t)};"function"==typeof Sizzle&&(ha=function(n,t){return Sizzle(n,t)[0]||null},ga=function(n,t){return Sizzle.uniqueSort(Sizzle(n,t))},va=Sizzle.matchesSelector),Xo.selection=function(){return xa};var da=Xo.selection.prototype=[];da.select=function(n){var t,e,r,u,i=[];n=M(n);for(var o=-1,a=this.length;++o=0&&(e=n.substring(0,t),n=n.substring(t+1)),ma.hasOwnProperty(e)?{space:ma[e],local:n}:n}},da.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Xo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(b(t,n[t]));return this}return this.each(b(n,t))},da.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=k(n)).length,u=-1;if(t=e.classList){for(;++ur){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(C(e,n[e],t));return this}if(2>r)return Go.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(C(n,t,e))},da.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(N(t,n[t]));return this}return this.each(N(n,t))},da.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},da.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},da.append=function(n){return n=L(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},da.insert=function(n,t){return n=L(n),t=M(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},da.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},da.data=function(n,t){function e(n,e){var r,i,o,a=n.length,f=e.length,h=Math.min(a,f),g=new Array(f),p=new Array(f),v=new Array(a);if(t){var d,m=new u,y=new u,x=[];for(r=-1;++rr;++r)p[r]=z(e[r]);for(;a>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,c.push(p),s.push(g),l.push(v)}var r,i,o=-1,a=this.length;if(!arguments.length){for(n=new Array(a=(r=this[0]).length);++oi;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return x(u)},da.order=function(){for(var n=-1,t=this.length;++n=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},da.sort=function(n){n=T.apply(this,arguments);for(var t=-1,e=this.length;++tn;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},da.size=function(){var n=0;return this.each(function(){++n}),n};var ya=[];Xo.selection.enter=D,Xo.selection.enter.prototype=ya,ya.append=da.append,ya.empty=da.empty,ya.node=da.node,ya.call=da.call,ya.size=da.size,ya.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++ar){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(j(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(j(n,t,e))};var Ma=Xo.map({mouseenter:"mouseover",mouseleave:"mouseout"});Ma.forEach(function(n){"on"+n in Wo&&Ma.remove(n)});var _a="onselectstart"in Wo?null:h(Jo.style,"userSelect"),ba=0;Xo.mouse=function(n){return Y(n,m())};var wa=/WebKit/.test(Go.navigator.userAgent)?-1:0;Xo.touches=function(n,t){return arguments.length<2&&(t=m().touches),t?Bo(t).map(function(t){var e=Y(n,t);return e.identifier=t.identifier,e}):[]},Xo.behavior.drag=function(){function n(){this.on("mousedown.drag",o).on("touchstart.drag",a)}function t(){return Xo.event.changedTouches[0].identifier}function e(n,t){return Xo.touches(n).filter(function(n){return n.identifier===t})[0]}function r(n,t,e,r){return function(){function o(){var n=t(l,g),e=n[0]-v[0],r=n[1]-v[1];d|=e|r,v=n,f({type:"drag",x:n[0]+c[0],y:n[1]+c[1],dx:e,dy:r})}function a(){m.on(e+"."+p,null).on(r+"."+p,null),y(d&&Xo.event.target===h),f({type:"dragend"})}var c,s=this,l=s.parentNode,f=u.of(s,arguments),h=Xo.event.target,g=n(),p=null==g?"drag":"drag-"+g,v=t(l,g),d=0,m=Xo.select(Go).on(e+"."+p,o).on(r+"."+p,a),y=O();i?(c=i.apply(s,arguments),c=[c.x-v[0],c.y-v[1]]):c=[0,0],f({type:"dragstart"})}}var u=y(n,"drag","dragstart","dragend"),i=null,o=r(g,Xo.mouse,"mousemove","mouseup"),a=r(t,e,"touchmove","touchend");return n.origin=function(t){return arguments.length?(i=t,n):i},Xo.rebind(n,u,"on")};var Sa=Math.PI,ka=2*Sa,Ea=Sa/2,Aa=1e-6,Ca=Aa*Aa,Na=Sa/180,La=180/Sa,za=Math.SQRT2,qa=2,Ta=4;Xo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=B(v),o=i/(qa*h)*(e*W(za*t+v)-$(v));return[r+o*s,u+o*l,i*e/B(za*t+v)]}return[r+n*s,u+n*l,i*Math.exp(za*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],s=o-r,l=a-u,f=s*s+l*l,h=Math.sqrt(f),g=(c*c-i*i+Ta*f)/(2*i*qa*h),p=(c*c-i*i-Ta*f)/(2*c*qa*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/za;return e.duration=1e3*y,e},Xo.behavior.zoom=function(){function n(n){n.on(A,s).on(Pa+".zoom",f).on(C,h).on("dblclick.zoom",g).on(L,l)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){_&&_.domain(M.range().map(function(n){return(n-S.x)/S.k}).map(M.invert)),w&&w.domain(b.range().map(function(n){return(n-S.y)/S.k}).map(b.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function s(){function n(){l=1,u(Xo.mouse(r),g),a(i)}function e(){f.on(C,Go===r?h:null).on(N,null),p(l&&Xo.event.target===s),c(i)}var r=this,i=z.of(r,arguments),s=Xo.event.target,l=0,f=Xo.select(Go).on(C,n).on(N,e),g=t(Xo.mouse(r)),p=O();U.call(r),o(i)}function l(){function n(){var n=Xo.touches(g);return h=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){for(var t=Xo.event.changedTouches,e=0,i=t.length;i>e;++e)v[t[e].identifier]=null;var o=n(),c=Date.now();if(1===o.length){if(500>c-x){var s=o[0],l=v[s.identifier];r(2*S.k),u(s,l),d(),a(p)}x=c}else if(o.length>1){var s=o[0],f=o[1],h=s[0]-f[0],g=s[1]-f[1];m=h*h+g*g}}function i(){for(var n,t,e,i,o=Xo.touches(g),c=0,s=o.length;s>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var l=(l=e[0]-n[0])*l+(l=e[1]-n[1])*l,f=m&&Math.sqrt(l/m);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*h)}x=null,u(n,t),a(p)}function f(){if(Xo.event.touches.length){for(var t=Xo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}b.on(M,null).on(_,null),w.on(A,s).on(L,l),k(),c(p)}var h,g=this,p=z.of(g,arguments),v={},m=0,y=Xo.event.changedTouches[0].identifier,M="touchmove.zoom-"+y,_="touchend.zoom-"+y,b=Xo.select(Go).on(M,i).on(_,f),w=Xo.select(g).on(A,null).on(L,e),k=O();U.call(g),e(),o(p)}function f(){var n=z.of(this,arguments);m?clearTimeout(m):(U.call(this),o(n)),m=setTimeout(function(){m=null,c(n)},50),d();var e=v||Xo.mouse(this);p||(p=t(e)),r(Math.pow(2,.002*Ra())*S.k),u(e,p),a(n)}function h(){p=null}function g(){var n=z.of(this,arguments),e=Xo.mouse(this),i=t(e),s=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Xo.event.shiftKey?Math.ceil(s)-1:Math.floor(s)+1)),u(e,i),a(n),c(n)}var p,v,m,x,M,_,b,w,S={x:0,y:0,k:1},k=[960,500],E=Da,A="mousedown.zoom",C="mousemove.zoom",N="mouseup.zoom",L="touchstart.zoom",z=y(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=z.of(this,arguments),t=S;ks?Xo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],u=e/2,i=r/2,o=Xo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?Da:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(v=t&&[+t[0],+t[1]],n):v},n.size=function(t){return arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.length?(_=t,M=t.copy(),S={x:0,y:0,k:1},n):_},n.y=function(t){return arguments.length?(w=t,b=t.copy(),S={x:0,y:0,k:1},n):w},Xo.rebind(n,z,"on")};var Ra,Da=[0,1/0],Pa="onwheel"in Wo?(Ra=function(){return-Xo.event.deltaY*(Xo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in Wo?(Ra=function(){return Xo.event.wheelDelta},"mousewheel"):(Ra=function(){return-Xo.event.detail},"MozMousePixelScroll");G.prototype.toString=function(){return this.rgb()+""},Xo.hsl=function(n,t,e){return 1===arguments.length?n instanceof Q?K(n.h,n.s,n.l):dt(""+n,mt,K):K(+n,+t,+e)};var Ua=Q.prototype=new G;Ua.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),K(this.h,this.s,this.l/n)},Ua.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),K(this.h,this.s,n*this.l)},Ua.rgb=function(){return nt(this.h,this.s,this.l)},Xo.hcl=function(n,t,e){return 1===arguments.length?n instanceof et?tt(n.h,n.c,n.l):n instanceof it?at(n.l,n.a,n.b):at((n=yt((n=Xo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):tt(+n,+t,+e)};var ja=et.prototype=new G;ja.brighter=function(n){return tt(this.h,this.c,Math.min(100,this.l+Ha*(arguments.length?n:1)))},ja.darker=function(n){return tt(this.h,this.c,Math.max(0,this.l-Ha*(arguments.length?n:1)))},ja.rgb=function(){return rt(this.h,this.c,this.l).rgb()},Xo.lab=function(n,t,e){return 1===arguments.length?n instanceof it?ut(n.l,n.a,n.b):n instanceof et?rt(n.l,n.c,n.h):yt((n=Xo.rgb(n)).r,n.g,n.b):ut(+n,+t,+e)};var Ha=18,Fa=.95047,Oa=1,Ya=1.08883,Ia=it.prototype=new G;Ia.brighter=function(n){return ut(Math.min(100,this.l+Ha*(arguments.length?n:1)),this.a,this.b)},Ia.darker=function(n){return ut(Math.max(0,this.l-Ha*(arguments.length?n:1)),this.a,this.b)},Ia.rgb=function(){return ot(this.l,this.a,this.b)},Xo.rgb=function(n,t,e){return 1===arguments.length?n instanceof pt?gt(n.r,n.g,n.b):dt(""+n,gt,nt):gt(~~n,~~t,~~e)};var Za=pt.prototype=new G;Za.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),gt(Math.min(255,~~(t/n)),Math.min(255,~~(e/n)),Math.min(255,~~(r/n)))):gt(u,u,u)},Za.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),gt(~~(n*this.r),~~(n*this.g),~~(n*this.b))},Za.hsl=function(){return mt(this.r,this.g,this.b)},Za.toString=function(){return"#"+vt(this.r)+vt(this.g)+vt(this.b)};var Va=Xo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});Va.forEach(function(n,t){Va.set(n,ft(t))}),Xo.functor=_t,Xo.xhr=wt(bt),Xo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=St(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(l>=s)return o;if(u)return u=!1,i;var t=l;if(34===n.charCodeAt(t)){for(var e=t;e++l;){var r=n.charCodeAt(l++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(l)&&(++l,++a);else if(r!==c)continue;return n.substring(t,l-a)}return n.substring(t)}for(var r,u,i={},o={},a=[],s=n.length,l=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();(!t||(h=t(h,f++)))&&a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new l,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},Xo.csv=Xo.dsv(",","text/csv"),Xo.tsv=Xo.dsv(" ","text/tab-separated-values");var Xa,$a,Ba,Wa,Ja,Ga=Go[h(Go,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Xo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};$a?$a.n=i:Xa=i,$a=i,Ba||(Wa=clearTimeout(Wa),Ba=1,Ga(Et))},Xo.timer.flush=function(){At(),Ct()},Xo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var Ka=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Lt);Xo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=Xo.round(n,Nt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((0>=e?e+1:e-1)/3)))),Ka[8+e/3]};var Qa=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,nc=Xo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=Xo.round(n,Nt(n,t))).toFixed(Math.max(0,Math.min(20,Nt(n*(1+1e-15),t))))}}),tc=Xo.time={},ec=Date;Tt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){rc.setUTCDate.apply(this._,arguments)},setDay:function(){rc.setUTCDay.apply(this._,arguments)},setFullYear:function(){rc.setUTCFullYear.apply(this._,arguments)},setHours:function(){rc.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){rc.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){rc.setUTCMinutes.apply(this._,arguments)},setMonth:function(){rc.setUTCMonth.apply(this._,arguments)},setSeconds:function(){rc.setUTCSeconds.apply(this._,arguments)},setTime:function(){rc.setTime.apply(this._,arguments)}};var rc=Date.prototype;tc.year=Rt(function(n){return n=tc.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),tc.years=tc.year.range,tc.years.utc=tc.year.utc.range,tc.day=Rt(function(n){var t=new ec(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),tc.days=tc.day.range,tc.days.utc=tc.day.utc.range,tc.dayOfYear=function(n){var t=tc.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=tc[n]=Rt(function(n){return(n=tc.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=tc.year(n).getDay();return Math.floor((tc.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});tc[n+"s"]=e.range,tc[n+"s"].utc=e.utc.range,tc[n+"OfYear"]=function(n){var e=tc.year(n).getDay();return Math.floor((tc.dayOfYear(n)+(e+t)%7)/7)}}),tc.week=tc.sunday,tc.weeks=tc.sunday.range,tc.weeks.utc=tc.sunday.utc.range,tc.weekOfYear=tc.sundayOfYear;var uc={"-":"",_:" ",0:"0"},ic=/^\s*\d+/,oc=/^%/;Xo.locale=function(n){return{numberFormat:zt(n),timeFormat:Pt(n)}};var ac=Xo.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Xo.format=ac.numberFormat,Xo.geo={},re.prototype={s:0,t:0,add:function(n){ue(n,this.t,cc),ue(cc.s,this.s,this),this.s?this.t+=cc.t:this.s=cc.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var cc=new re;Xo.geo.stream=function(n,t){n&&sc.hasOwnProperty(n.type)?sc[n.type](n,t):ie(n,t)};var sc={Feature:function(n,t){ie(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++rn?4*Sa+n:n,gc.lineStart=gc.lineEnd=gc.point=g}};Xo.geo.bounds=function(){function n(n,t){x.push(M=[l=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=se([t*Na,e*Na]);if(m){var u=fe(m,r),i=[u[1],-u[0],0],o=fe(i,u);pe(o),o=ve(o);var c=t-p,s=c>0?1:-1,v=o[0]*La*s,d=oa(c)>180;if(d^(v>s*p&&s*t>v)){var y=o[1]*La;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>s*p&&s*t>v)){var y=-o[1]*La;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t):h>=l?(l>t&&(l=t),t>h&&(h=t)):t>p?a(l,t)>a(l,h)&&(h=t):a(t,h)>a(l,h)&&(l=t)}else n(t,e);m=r,p=t}function e(){_.point=t}function r(){M[0]=l,M[1]=h,_.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=oa(r)>180?r+(r>0?360:-360):r}else v=n,d=e;gc.point(n,e),t(n,e)}function i(){gc.lineStart()}function o(){u(v,d),gc.lineEnd(),oa(y)>Aa&&(l=-(h=180)),M[0]=l,M[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function s(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nhc?(l=-(h=180),f=-(g=90)):y>Aa?g=90:-Aa>y&&(f=-90),M[0]=l,M[1]=h +}};return function(n){g=h=-(l=f=1/0),x=[],Xo.geo.stream(n,_);var t=x.length;if(t){x.sort(c);for(var e,r=1,u=x[0],i=[u];t>r;++r)e=x[r],s(e[0],u)||s(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,l=e[0],h=u[1])}return x=M=null,1/0===l||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[l,f],[h,g]]}}(),Xo.geo.centroid=function(n){pc=vc=dc=mc=yc=xc=Mc=_c=bc=wc=Sc=0,Xo.geo.stream(n,kc);var t=bc,e=wc,r=Sc,u=t*t+e*e+r*r;return Ca>u&&(t=xc,e=Mc,r=_c,Aa>vc&&(t=dc,e=mc,r=yc),u=t*t+e*e+r*r,Ca>u)?[0/0,0/0]:[Math.atan2(e,t)*La,X(r/Math.sqrt(u))*La]};var pc,vc,dc,mc,yc,xc,Mc,_c,bc,wc,Sc,kc={sphere:g,point:me,lineStart:xe,lineEnd:Me,polygonStart:function(){kc.lineStart=_e},polygonEnd:function(){kc.lineStart=xe}},Ec=Ee(be,ze,Te,[-Sa,-Sa/2]),Ac=1e9;Xo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Pe(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(Xo.geo.conicEqualArea=function(){return je(He)}).raw=He,Xo.geo.albers=function(){return Xo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Xo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=Xo.geo.albers(),o=Xo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Xo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var s=i.scale(),l=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[l-.455*s,f-.238*s],[l+.455*s,f+.238*s]]).stream(c).point,r=o.translate([l-.307*s,f+.201*s]).clipExtent([[l-.425*s+Aa,f+.12*s+Aa],[l-.214*s-Aa,f+.234*s-Aa]]).stream(c).point,u=a.translate([l-.205*s,f+.212*s]).clipExtent([[l-.214*s+Aa,f+.166*s+Aa],[l-.115*s-Aa,f+.234*s-Aa]]).stream(c).point,n},n.scale(1070)};var Cc,Nc,Lc,zc,qc,Tc,Rc={point:g,lineStart:g,lineEnd:g,polygonStart:function(){Nc=0,Rc.lineStart=Fe},polygonEnd:function(){Rc.lineStart=Rc.lineEnd=Rc.point=g,Cc+=oa(Nc/2)}},Dc={point:Oe,lineStart:g,lineEnd:g,polygonStart:g,polygonEnd:g},Pc={point:Ze,lineStart:Ve,lineEnd:Xe,polygonStart:function(){Pc.lineStart=$e},polygonEnd:function(){Pc.point=Ze,Pc.lineStart=Ve,Pc.lineEnd=Xe}};Xo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Xo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return Cc=0,Xo.geo.stream(n,u(Rc)),Cc},n.centroid=function(n){return dc=mc=yc=xc=Mc=_c=bc=wc=Sc=0,Xo.geo.stream(n,u(Pc)),Sc?[bc/Sc,wc/Sc]:_c?[xc/_c,Mc/_c]:yc?[dc/yc,mc/yc]:[0/0,0/0]},n.bounds=function(n){return qc=Tc=-(Lc=zc=1/0),Xo.geo.stream(n,u(Dc)),[[Lc,zc],[qc,Tc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||Je(n):bt,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new Ye:new Be(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(Xo.geo.albersUsa()).context(null)},Xo.geo.transform=function(n){return{stream:function(t){var e=new Ge(t);for(var r in n)e[r]=n[r];return e}}},Ge.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},Xo.geo.projection=Qe,Xo.geo.projectionMutator=nr,(Xo.geo.equirectangular=function(){return Qe(er)}).raw=er.invert=er,Xo.geo.rotation=function(n){function t(t){return t=n(t[0]*Na,t[1]*Na),t[0]*=La,t[1]*=La,t}return n=ur(n[0]%360*Na,n[1]*Na,n.length>2?n[2]*Na:0),t.invert=function(t){return t=n.invert(t[0]*Na,t[1]*Na),t[0]*=La,t[1]*=La,t},t},rr.invert=er,Xo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=ur(-n[0]*Na,-n[1]*Na,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=La,n[1]*=La}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=cr((t=+r)*Na,u*Na),n):t},n.precision=function(r){return arguments.length?(e=cr(t*Na,(u=+r)*Na),n):u},n.angle(90)},Xo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*Na,u=n[1]*Na,i=t[1]*Na,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),s=Math.cos(u),l=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=s*l-c*f*a)*e),c*l+s*f*a)},Xo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return Xo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Xo.range(Math.ceil(s/m)*m,c,m).map(g)).concat(Xo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return oa(n%d)>Aa}).map(l)).concat(Xo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return oa(n%m)>Aa}).map(f))}var e,r,u,i,o,a,c,s,l,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],s=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),s>c&&(t=s,s=c,c=t),n.precision(y)):[[i,s],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,l=lr(a,o,90),f=fr(r,e,y),h=lr(s,c,90),g=fr(i,u,y),n):y},n.majorExtent([[-180,-90+Aa],[180,90-Aa]]).minorExtent([[-180,-80-Aa],[180,80+Aa]])},Xo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=hr,u=gr;return n.distance=function(){return Xo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},Xo.geo.interpolate=function(n,t){return pr(n[0]*Na,n[1]*Na,t[0]*Na,t[1]*Na)},Xo.geo.length=function(n){return Uc=0,Xo.geo.stream(n,jc),Uc};var Uc,jc={sphere:g,point:g,lineStart:vr,lineEnd:g,polygonStart:g,polygonEnd:g},Hc=dr(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(Xo.geo.azimuthalEqualArea=function(){return Qe(Hc)}).raw=Hc;var Fc=dr(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},bt);(Xo.geo.azimuthalEquidistant=function(){return Qe(Fc)}).raw=Fc,(Xo.geo.conicConformal=function(){return je(mr)}).raw=mr,(Xo.geo.conicEquidistant=function(){return je(yr)}).raw=yr;var Oc=dr(function(n){return 1/n},Math.atan);(Xo.geo.gnomonic=function(){return Qe(Oc)}).raw=Oc,xr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ea]},(Xo.geo.mercator=function(){return Mr(xr)}).raw=xr;var Yc=dr(function(){return 1},Math.asin);(Xo.geo.orthographic=function(){return Qe(Yc)}).raw=Yc;var Ic=dr(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(Xo.geo.stereographic=function(){return Qe(Ic)}).raw=Ic,_r.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ea]},(Xo.geo.transverseMercator=function(){var n=Mr(_r),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[-n[1],n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},n.rotate([0,0])}).raw=_r,Xo.geom={},Xo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=_t(e),i=_t(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(kr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var s=Sr(a),l=Sr(c),f=l[0]===s[0],h=l[l.length-1]===s[s.length-1],g=[];for(t=s.length-1;t>=0;--t)g.push(n[a[s[t]][2]]);for(t=+f;t=r&&s.x<=i&&s.y>=u&&s.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];l.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Aa)*Aa,y:Math.round(o(n,t)/Aa)*Aa,i:t}})}var r=br,u=wr,i=r,o=u,a=Kc;return n?t(n):(t.links=function(n){return nu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return nu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(jr),c=-1,s=a.length,l=a[s-1].edge,f=l.l===o?l.r:l.l;++c=s,h=r>=l,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=iu()),f?u=s:a=s,h?o=l:c=l,i(n,t,e,r,u,o,a,c)}var l,f,h,g,p,v,d,m,y,x=_t(a),M=_t(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)l=n[g],l.xm&&(m=l.x),l.y>y&&(y=l.y),f.push(l.x),h.push(l.y);else for(g=0;p>g;++g){var _=+x(l=n[g],g),b=+M(l,g);v>_&&(v=_),d>b&&(d=b),_>m&&(m=_),b>y&&(y=b),f.push(_),h.push(b)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=iu();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){ou(n,k,v,d,m,y)},g=-1,null==t){for(;++g=0?n.substring(0,t):n,r=t>=0?n.substring(t+1):"in";return e=ts.get(e)||ns,r=es.get(r)||bt,gu(r(e.apply(null,$o.call(arguments,1))))},Xo.interpolateHcl=Eu,Xo.interpolateHsl=Au,Xo.interpolateLab=Cu,Xo.interpolateRound=Nu,Xo.transform=function(n){var t=Wo.createElementNS(Xo.ns.prefix.svg,"g");return(Xo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Lu(e?e.matrix:rs)})(n)},Lu.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var rs={a:1,b:0,c:0,d:1,e:0,f:0};Xo.interpolateTransform=Ru,Xo.layout={},Xo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++ea*a/d){if(p>c){var s=t.charge/c;n.px-=i*s,n.py-=o*s}return!0}if(t.point&&c&&p>c){var s=t.pointCharge/c;n.px-=i*s,n.py-=o*s}}return!t.charge}}function t(n){n.px=Xo.event.x,n.py=Xo.event.y,a.resume()}var e,r,u,i,o,a={},c=Xo.dispatch("start","tick","end"),s=[1,1],l=.9,f=us,h=is,g=-30,p=os,v=.1,d=.64,m=[],y=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,x,M,_=m.length,b=y.length;for(e=0;b>e;++e)a=y[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(p=x*x+M*M)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,x*=p,M*=p,h.x-=x*(d=f.weight/(h.weight+f.weight)),h.y-=M*d,f.x+=x*(d=1-d),f.y+=M*d);if((d=r*v)&&(x=s[0]/2,M=s[1]/2,e=-1,d))for(;++e<_;)a=m[e],a.x+=(x-a.x)*d,a.y+=(M-a.y)*d;if(g)for(Zu(t=Xo.geom.quadtree(m),r,o),e=-1;++e<_;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*l,a.y-=(a.py-(a.py=a.y))*l);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(y=n,a):y},a.size=function(n){return arguments.length?(s=n,a):s},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(l=+n,a):l},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Xo.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;s>a;++a){var u=y[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,s=o.length;++at;++t)(r=m[t]).index=t,r.weight=0;for(t=0;l>t;++t)r=y[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;l>t;++t)u[t]=+f.call(this,y[t],t);else for(t=0;l>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;l>t;++t)i[t]=+h.call(this,y[t],t);else for(t=0;l>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Xo.behavior.drag().origin(bt).on("dragstart.force",Fu).on("drag.force",t).on("dragend.force",Ou)),arguments.length?(this.on("mouseover.force",Yu).on("mouseout.force",Iu).call(e),void 0):e},Xo.rebind(a,c,"on")};var us=20,is=1,os=1/0;Xo.layout.hierarchy=function(){function n(t,o,a){var c=u.call(e,t,o);if(t.depth=o,a.push(t),c&&(s=c.length)){for(var s,l,f=-1,h=t.children=new Array(s),g=0,p=o+1;++fg;++g)for(u.call(n,s[0][g],p=v[g],l[0][g][1]),h=1;d>h;++h)u.call(n,s[h][g],p+=l[h-1][g][1],l[h][g][1]);return a}var t=bt,e=Qu,r=ni,u=Ku,i=Ju,o=Gu;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:cs.get(t)||Qu,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:ss.get(t)||ni,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var cs=Xo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(ti),i=n.map(ei),o=Xo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,s=[],l=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],s.push(e)):(c+=i[e],l.push(e));return l.reverse().concat(s)},reverse:function(n){return Xo.range(n.length).reverse()},"default":Qu}),ss=Xo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,s,l=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=s=0,e=1;h>e;++e){for(t=0,u=0;l>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];l>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,s>c&&(s=c)}for(e=0;h>e;++e)g[e]-=s;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ni});Xo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],s=n.map(e,this),l=r.call(this,s,i),f=u.call(this,l,s,i),i=-1,h=s.length,g=f.length-1,p=t?1:1/h;++i0)for(i=-1;++i=l[0]&&a<=l[1]&&(o=c[Xo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=oi,u=ui;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=_t(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return ii(n,t)}:_t(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},Xo.layout.tree=function(){function n(n,i){function o(n,t){var r=n.children,u=n._tree;if(r&&(i=r.length)){for(var i,a,s,l=r[0],f=l,h=-1;++h0&&(di(mi(a,n,r),n,u),s+=u,l+=u),f+=a._tree.mod,s+=i._tree.mod,h+=c._tree.mod,l+=o._tree.mod;a&&!si(o)&&(o._tree.thread=a,o._tree.mod+=f-l),i&&!ci(c)&&(c._tree.thread=i,c._tree.mod+=s-h,r=n)}return r}var s=t.call(this,n,i),l=s[0];pi(l,function(n,t){n._tree={ancestor:n,prelim:0,mod:0,change:0,shift:0,number:t?t._tree.number+1:0}}),o(l),a(l,-l._tree.prelim);var f=li(l,hi),h=li(l,fi),g=li(l,gi),p=f.x-e(f,h)/2,v=h.x+e(h,f)/2,d=g.depth||1;return pi(l,u?function(n){n.x*=r[0],n.y=n.depth*r[1],delete n._tree}:function(n){n.x=(n.x-p)/(v-p)*r[0],n.y=n.depth/d*r[1],delete n._tree}),s}var t=Xo.layout.hierarchy().sort(null).value(null),e=ai,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Vu(n,t)},Xo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],s=u[1],l=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,pi(a,function(n){n.r=+l(n.value)}),pi(a,bi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/s))/2;pi(a,function(n){n.r+=f}),pi(a,bi),pi(a,function(n){n.r-=f})}return ki(a,c/2,s/2,t?1:1/Math.max(2*a.r/c,2*a.r/s)),o}var t,e=Xo.layout.hierarchy().sort(yi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Vu(n,e)},Xo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],s=0;pi(c,function(n){var t=n.children;t&&t.length?(n.x=Ci(t),n.y=Ai(t)):(n.x=o?s+=e(n,o):0,n.y=0,o=n)});var l=Ni(c),f=Li(c),h=l.x-e(l,f)/2,g=f.x+e(f,l)/2;return pi(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=Xo.layout.hierarchy().sort(null).value(null),e=ai,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Vu(n,t)},Xo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++ut?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,s=f(e),l=[],h=i.slice(),p=1/0,v="slice"===g?s.dx:"dice"===g?s.dy:"slice-dice"===g?1&e.depth?s.dy:s.dx:Math.min(s.dx,s.dy);for(n(h,s.dx*s.dy/e.value),l.area=0;(c=h.length)>0;)l.push(o=h[c-1]),l.area+=o.area,"squarify"!==g||(a=r(l,v))<=p?(h.pop(),p=a):(l.area-=l.pop().area,u(l,v,s,!1),v=Math.min(s.dx,s.dy),l.length=l.area=0,p=1/0);l.length&&(u(l,v,s,!0),l.length=l.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++oe&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,s=e.y,l=t?c(n.area/t):0;if(t==e.dx){for((r||l>e.dy)&&(l=e.dy);++ie.dx)&&(l=e.dx);++ie&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=Xo.random.normal.apply(Xo,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=Xo.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},Xo.scale={};var ls={floor:bt,ceil:bt};Xo.scale.linear=function(){return Hi([0,1],[0,1],fu,!1)};var fs={s:1,g:1,p:1,r:1,e:1};Xo.scale.log=function(){return $i(Xo.scale.linear().domain([0,1]),10,!0,[1,10])};var hs=Xo.format(".0e"),gs={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Xo.scale.pow=function(){return Bi(Xo.scale.linear(),1,[0,1])},Xo.scale.sqrt=function(){return Xo.scale.pow().exponent(.5)},Xo.scale.ordinal=function(){return Ji([],{t:"range",a:[[]]})},Xo.scale.category10=function(){return Xo.scale.ordinal().range(ps)},Xo.scale.category20=function(){return Xo.scale.ordinal().range(vs)},Xo.scale.category20b=function(){return Xo.scale.ordinal().range(ds)},Xo.scale.category20c=function(){return Xo.scale.ordinal().range(ms)};var ps=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(ht),vs=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(ht),ds=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(ht),ms=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(ht);Xo.scale.quantile=function(){return Gi([],[]) +},Xo.scale.quantize=function(){return Ki(0,1,[0,1])},Xo.scale.threshold=function(){return Qi([.5],[0,1])},Xo.scale.identity=function(){return no([0,1])},Xo.svg={},Xo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+ys,a=u.apply(this,arguments)+ys,c=(o>a&&(c=o,o=a,a=c),a-o),s=Sa>c?"0":"1",l=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a);return c>=xs?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+s+",0 "+n*l+","+n*f+"Z":"M"+i*l+","+i*f+"A"+i+","+i+" 0 "+s+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=to,e=eo,r=ro,u=uo;return n.innerRadius=function(e){return arguments.length?(t=_t(e),n):t},n.outerRadius=function(t){return arguments.length?(e=_t(t),n):e},n.startAngle=function(t){return arguments.length?(r=_t(t),n):r},n.endAngle=function(t){return arguments.length?(u=_t(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+ys;return[Math.cos(i)*n,Math.sin(i)*n]},n};var ys=-Ea,xs=ka-Aa;Xo.svg.line=function(){return io(bt)};var Ms=Xo.map({linear:oo,"linear-closed":ao,step:co,"step-before":so,"step-after":lo,basis:mo,"basis-open":yo,"basis-closed":xo,bundle:Mo,cardinal:go,"cardinal-open":fo,"cardinal-closed":ho,monotone:Eo});Ms.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var _s=[0,2/3,1/3,0],bs=[0,1/3,2/3,0],ws=[0,1/6,2/3,1/6];Xo.svg.line.radial=function(){var n=io(Ao);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},so.reverse=lo,lo.reverse=so,Xo.svg.area=function(){return Co(bt)},Xo.svg.area.radial=function(){var n=Co(Ao);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},Xo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),s=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,s)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,s.r,s.p0)+r(s.r,s.p1,s.a1-s.a0)+u(s.r,s.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+ys,l=s.call(n,u,r)+ys;return{r:i,a0:o,a1:l,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(l),i*Math.sin(l)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Sa)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=hr,o=gr,a=No,c=ro,s=uo;return n.radius=function(t){return arguments.length?(a=_t(t),n):a},n.source=function(t){return arguments.length?(i=_t(t),n):i},n.target=function(t){return arguments.length?(o=_t(t),n):o},n.startAngle=function(t){return arguments.length?(c=_t(t),n):c},n.endAngle=function(t){return arguments.length?(s=_t(t),n):s},n},Xo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=hr,e=gr,r=Lo;return n.source=function(e){return arguments.length?(t=_t(e),n):t},n.target=function(t){return arguments.length?(e=_t(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},Xo.svg.diagonal.radial=function(){var n=Xo.svg.diagonal(),t=Lo,e=n.projection;return n.projection=function(n){return arguments.length?e(zo(t=n)):t},n},Xo.svg.symbol=function(){function n(n,r){return(Ss.get(t.call(this,n,r))||Ro)(e.call(this,n,r))}var t=To,e=qo;return n.type=function(e){return arguments.length?(t=_t(e),n):t},n.size=function(t){return arguments.length?(e=_t(t),n):e},n};var Ss=Xo.map({circle:Ro,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Cs)),e=t*Cs;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/As),e=t*As/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/As),e=t*As/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});Xo.svg.symbolTypes=Ss.keys();var ks,Es,As=Math.sqrt(3),Cs=Math.tan(30*Na),Ns=[],Ls=0;Ns.call=da.call,Ns.empty=da.empty,Ns.node=da.node,Ns.size=da.size,Xo.transition=function(n){return arguments.length?ks?n.transition():n:xa.transition()},Xo.transition.prototype=Ns,Ns.select=function(n){var t,e,r,u=this.id,i=[];n=M(n);for(var o=-1,a=this.length;++oi;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Do(u,this.id)},Ns.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):R(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Ns.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Ru:fu,a=Xo.ns.qualify(n);return Po(this,"attr."+n,t,a.local?i:u)},Ns.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=Xo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Ns.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=Go.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=fu(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return Po(this,"style."+n,t,u)},Ns.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,Go.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Ns.text=function(n){return Po(this,"text",n,Uo)},Ns.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Ns.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=Xo.ease.apply(Xo,arguments)),R(this,function(e){e.__transition__[t].ease=n}))},Ns.delay=function(n){var t=this.id;return R(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Ns.duration=function(n){var t=this.id;return R(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Ns.each=function(n,t){var e=this.id;if(arguments.length<2){var r=Es,u=ks;ks=e,R(this,function(t,r,u){Es=t.__transition__[e],n.call(t,t.__data__,r,u)}),Es=r,ks=u}else R(this,function(r){var u=r.__transition__[e];(u.event||(u.event=Xo.dispatch("start","end"))).on(n,t)});return this},Ns.transition=function(){for(var n,t,e,r,u=this.id,i=++Ls,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],s=0,l=t.length;l>s;s++)(e=t[s])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,jo(e,s,i,r)),n.push(e)}return Do(o,i)},Xo.svg.axis=function(){function n(n){n.each(function(){var n,s=Xo.select(this),l=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):bt:t,p=s.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Aa),d=Xo.transition(p.exit()).style("opacity",Aa).remove(),m=Xo.transition(p).style("opacity",1),y=Ri(f),x=s.selectAll(".domain").data([0]),M=(x.enter().append("path").attr("class","domain"),Xo.transition(x));v.append("line"),v.append("text");var _=v.select("line"),b=m.select("line"),w=p.select("text").text(g),S=v.select("text"),k=m.select("text");switch(r){case"bottom":n=Ho,_.attr("y2",u),S.attr("y",Math.max(u,0)+o),b.attr("x2",0).attr("y2",u),k.attr("x",0).attr("y",Math.max(u,0)+o),w.attr("dy",".71em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+i+"V0H"+y[1]+"V"+i);break;case"top":n=Ho,_.attr("y2",-u),S.attr("y",-(Math.max(u,0)+o)),b.attr("x2",0).attr("y2",-u),k.attr("x",0).attr("y",-(Math.max(u,0)+o)),w.attr("dy","0em").style("text-anchor","middle"),M.attr("d","M"+y[0]+","+-i+"V0H"+y[1]+"V"+-i);break;case"left":n=Fo,_.attr("x2",-u),S.attr("x",-(Math.max(u,0)+o)),b.attr("x2",-u).attr("y2",0),k.attr("x",-(Math.max(u,0)+o)).attr("y",0),w.attr("dy",".32em").style("text-anchor","end"),M.attr("d","M"+-i+","+y[0]+"H0V"+y[1]+"H"+-i);break;case"right":n=Fo,_.attr("x2",u),S.attr("x",Math.max(u,0)+o),b.attr("x2",u).attr("y2",0),k.attr("x",Math.max(u,0)+o).attr("y",0),w.attr("dy",".32em").style("text-anchor","start"),M.attr("d","M"+i+","+y[0]+"H0V"+y[1]+"H"+i)}if(f.rangeBand){var E=f,A=E.rangeBand()/2;l=f=function(n){return E(n)+A}}else l.rangeBand?l=f:d.call(n,f);v.call(n,l),m.call(n,f)})}var t,e=Xo.scale.linear(),r=zs,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in qs?t+"":zs,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var zs="bottom",qs={top:1,right:1,bottom:1,left:1};Xo.svg.brush=function(){function n(i){i.each(function(){var i=Xo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(p,bt);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Ts[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var l,f=Xo.transition(i),h=Xo.transition(o);c&&(l=Ri(c),h.attr("x",l[0]).attr("width",l[1]-l[0]),e(f)),s&&(l=Ri(s),h.attr("y",l[0]).attr("height",l[1]-l[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+l[+/e$/.test(n)]+","+f[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",l[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",l[1]-l[0])}function r(n){n.select(".extent").attr("y",f[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1]-f[0])}function u(){function u(){32==Xo.event.keyCode&&(C||(x=null,L[0]-=l[1],L[1]-=f[1],C=2),d())}function p(){32==Xo.event.keyCode&&2==C&&(L[0]+=l[1],L[1]+=f[1],C=0,d())}function v(){var n=Xo.mouse(_),u=!1;M&&(n[0]+=M[0],n[1]+=M[1]),C||(Xo.event.altKey?(x||(x=[(l[0]+l[1])/2,(f[0]+f[1])/2]),L[0]=l[+(n[0]p?(u=r,r=p):u=p),v[0]!=r||v[1]!=u?(e?o=null:i=null,v[0]=r,v[1]=u,!0):void 0}function y(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Xo.select("body").style("cursor",null),z.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),N(),w({type:"brushend"})}var x,M,_=this,b=Xo.select(Xo.event.target),w=a.of(_,arguments),S=Xo.select(_),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&s,C=b.classed("extent"),N=O(),L=Xo.mouse(_),z=Xo.select(Go).on("keydown.brush",u).on("keyup.brush",p);if(Xo.event.changedTouches?z.on("touchmove.brush",v).on("touchend.brush",y):z.on("mousemove.brush",v).on("mouseup.brush",y),S.interrupt().selectAll("*").interrupt(),C)L[0]=l[0]-L[0],L[1]=f[0]-L[1];else if(k){var q=+/w$/.test(k),T=+/^n/.test(k);M=[l[1-q]-L[0],f[1-T]-L[1]],L[0]=l[q],L[1]=f[T]}else Xo.event.altKey&&(x=L.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),Xo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=y(n,"brushstart","brush","brushend"),c=null,s=null,l=[0,0],f=[0,0],h=!0,g=!0,p=Rs[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:l,y:f,i:i,j:o},e=this.__chart__||t;this.__chart__=t,ks?Xo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,l=e.x,f=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=hu(l,t.x),r=hu(f,t.y);return i=o=null,function(u){l=t.x=e(u),f=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,p=Rs[!c<<1|!s],n):c},n.y=function(t){return arguments.length?(s=t,p=Rs[!c<<1|!s],n):s},n.clamp=function(t){return arguments.length?(c&&s?(h=!!t[0],g=!!t[1]):c?h=!!t:s&&(g=!!t),n):c&&s?[h,g]:c?h:s?g:null},n.extent=function(t){var e,r,u,a,h;return arguments.length?(c&&(e=t[0],r=t[1],s&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(h=e,e=r,r=h),(e!=l[0]||r!=l[1])&&(l=[e,r])),s&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],s.invert&&(u=s(u),a=s(a)),u>a&&(h=u,u=a,a=h),(u!=f[0]||a!=f[1])&&(f=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=l[0],r=l[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(h=e,e=r,r=h))),s&&(o?(u=o[0],a=o[1]):(u=f[0],a=f[1],s.invert&&(u=s.invert(u),a=s.invert(a)),u>a&&(h=u,u=a,a=h))),c&&s?[[e,u],[r,a]]:c?[e,r]:s&&[u,a])},n.clear=function(){return n.empty()||(l=[0,0],f=[0,0],i=o=null),n},n.empty=function(){return!!c&&l[0]==l[1]||!!s&&f[0]==f[1]},Xo.rebind(n,a,"on")};var Ts={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Rs=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],Ds=tc.format=ac.timeFormat,Ps=Ds.utc,Us=Ps("%Y-%m-%dT%H:%M:%S.%LZ");Ds.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Oo:Us,Oo.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Oo.toString=Us.toString,tc.second=Rt(function(n){return new ec(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),tc.seconds=tc.second.range,tc.seconds.utc=tc.second.utc.range,tc.minute=Rt(function(n){return new ec(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),tc.minutes=tc.minute.range,tc.minutes.utc=tc.minute.utc.range,tc.hour=Rt(function(n){var t=n.getTimezoneOffset()/60;return new ec(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),tc.hours=tc.hour.range,tc.hours.utc=tc.hour.utc.range,tc.month=Rt(function(n){return n=tc.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),tc.months=tc.month.range,tc.months.utc=tc.month.utc.range;var js=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Hs=[[tc.second,1],[tc.second,5],[tc.second,15],[tc.second,30],[tc.minute,1],[tc.minute,5],[tc.minute,15],[tc.minute,30],[tc.hour,1],[tc.hour,3],[tc.hour,6],[tc.hour,12],[tc.day,1],[tc.day,2],[tc.week,1],[tc.month,1],[tc.month,3],[tc.year,1]],Fs=Ds.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",be]]),Os={range:function(n,t,e){return Xo.range(+n,+t,e).map(Io)},floor:bt,ceil:bt};Hs.year=tc.year,tc.scale=function(){return Yo(Xo.scale.linear(),Hs,Fs)};var Ys=Hs.map(function(n){return[n[0].utc,n[1]]}),Is=Ps.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",be]]);Ys.year=tc.year.utc,tc.scale.utc=function(){return Yo(Xo.scale.linear(),Ys,Is)},Xo.text=wt(function(n){return n.responseText}),Xo.json=function(n,t){return St(n,"application/json",Zo,t)},Xo.html=function(n,t){return St(n,"text/html",Vo,t)},Xo.xml=wt(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(Xo):"object"==typeof module&&module.exports?module.exports=Xo:this.d3=Xo}(); diff --git a/vowl_v2/data/favicon.ico b/vowl_v2/data/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8839b0885331b01b41db14cc23439f255ab343f9 GIT binary patch literal 1406 zcmeH_`!keL7{|X$a*55lv&y2Il-($A+LDMaWJ@kdg_5jGybgA4jcL*^ri(7qWf+l0 zis^naHT}>uX8Or=aVcS$-KL4DP-8+<+q26b&>!Hu^EuBs&pFTcJkqY52l^|#dMs^w{1fR3vL2wEg2%fnydN^2T)))u0JIG!Gbh`c$`wk;AB=b^5W!B zDnhVc>H~fAQRr?RfsXVBZfc+<&0f;$X;7j2dI{cNGwK$TW)WI103-(kVe#y%81M9fkPNScdMV za(rw)fu1`R=)HFeeGkr{_x@>UADu^k%S8-4y@F3KZ{YK*+Zb$nf}uChFw)nC5$$V? z_P@oiuX>CRf5E3_4J2+N1pCcHtvV6j?hZIh=jwY{NpX+y?R_hL=sGYqsKvzS5JXfH z7m+Q*&U5kS_XH-#h9RIj8Vm-q(*>O>>r6j$1OIgc^mYseW@@IPX=Wa^U+(Tvz)T*N z7r8<@e|~^$;Q^zAMK2Hs`)=OqEs?HHBS+!d<($*DYzu{mldge*IR*uD)=50S%bJtS zTgKQXF~?2g> zM_6TLyLwAEFy`!Kuiy_^*(CBiMS 0 && version <= 11) { + var graph = document.getElementById('graph') + , controlDetails = document.getElementById('controlDetails') + , browserCheck = document.getElementById('browserCheck'); + // hiding any additional menus and features + + graph.style.display = "none"; + controlDetails.style.display = "none"; + browserCheck.style.display = "block"; + + browserCheck.innerHTML = "The WebVOWL demo does not work in Internet Explorer. Please use another browser, such as Mozilla Firefox or Google Chrome, to see the demo."; +} diff --git a/vowl_v2/data/specVOWL.js b/vowl_v2/data/specVOWL.js new file mode 100644 index 00000000..8c63ca84 --- /dev/null +++ b/vowl_v2/data/specVOWL.js @@ -0,0 +1,59 @@ +var graphTag = document.getElementById('graph') + , linkDistanceClassSlider + , linkDistanceClassLabel + , linkDistanceLiteralLabel + , linkDistanceLiteralSlider + , onLoadCalled = false; +// Set the default graph data +var jsonURI = "foaf_spec"; + +var graphOptions = function graphOptionsFunct() { + + var resetOption = document.getElementById('resetOption') + , sliderOption = document.getElementById('sliderOption'); + + d3.select(resetOption) + .append("button") + .attr("id", "reset") + .property("type", "reset") + .text("Reset") + .on("click", resetGraph); + + var slidDiv = d3.select(sliderOption) + .append("div") + .attr("id", "distanceSlider"); + + linkDistanceClassLabel = slidDiv.append("label") + .attr("for", "distanceSlider") + .text(DEFAULT_VISIBLE_LINKDISTANCE); + linkDistanceLiteralLabel = linkDistanceClassLabel; + + linkDistanceClassSlider = slidDiv.append("input") + .attr("type", "range") + .attr("min", 10) + .attr("max", 600) + .attr("value", DEFAULT_VISIBLE_LINKDISTANCE) + .attr("step", 10) + .on("input", changeDistance); + linkDistanceLiteralSlider = linkDistanceClassSlider; +}; + +var loadGraph = function loadGraphFunct() { + var height = 600 + , width = document.getElementById("example").offsetWidth; + + d3.json("js/data/" + jsonURI + ".json", function(error, data) { + json = data; + drawGraph(graphTag, width, height); + }); +}; + +var onload = function onloadFunct() { + // Prevent multiple executions of the onload function + if (onLoadCalled) { + return; + } + onLoadCalled = true; + loadGraph(); +}; +document.onload = onload(); diff --git a/vowl_v2/data/vowl.css b/vowl_v2/data/vowl.css new file mode 100644 index 00000000..ad638748 --- /dev/null +++ b/vowl_v2/data/vowl.css @@ -0,0 +1,111 @@ +/*----------------------------------------------------------------- + VOWL graphical elements (part of spec) - mixed CSS and SVG styles +-----------------------------------------------------------------*/ + +/*-------- Text --------*/ +text { + font-family: Helvetica, Arial, sans-serif; + font-size: 12px; +} +.subtext { + font-size: 9px; +} +.cardinality { + font-size: 10px; +} +.text, .resulttext, .embedded { + pointer-events: none; +} + +/*------- Strokes ------*/ +.class, path { + stroke-width: 2; +} +.fineline { + stroke-width: 1; +} +.special { + stroke-dasharray: 8; +} +.dotted { + stroke-dasharray: 3; +} +rect.focused, circle.focused { + stroke-width: 4px; +} +.nostroke { + stroke: none; +} + +/*------- Colors ------*/ +.class, .object, .disjoint { + fill: #acf; +} +.label .datatype { + fill: #9c6; +} +.rdf { + fill: #c9c; +} +.literal, .node .datatype { + fill: #fc3; +} +.deprecated { + fill: #ccc; +} +.external { + fill: #36c; +} +.symbol { + fill: #69c; +} +.arrowhead, marker path { + fill: #000; +} +.class, path, .fineline { + stroke: #000; +} +.white, .subclass, .dottedMarker path { + fill: #fff; +} +path, .nofill { + fill: none; +} +.class:hover, .property:hover, path.arrowhead.hovered, .cardinality.hovered, .normalMarker path.hovered, .cardinality.focused, .normalMarker path.focused { + fill: #f00; + cursor: pointer; +} +.focused, path.hovered { + stroke: #f00; +} +.label .indirectHighlighting { + fill: #f90; +} + +/*--- "resulttext" is required for QueryVOWL (added on May 29, 2015) ------*/ +.resulttext { + fill: #696969; +} + + +/*----------------------------------------------------------------- + Additional elements for the WebVOWL demo (NOT part of spec) +-----------------------------------------------------------------*/ + +#width-test { + position: absolute; + float: left; + white-space: nowrap; + visibility: hidden; +} + +.svgGraph .text tspan:only-child, .svgGraph .text:empty { /* labels with one line and nodes */ + dominant-baseline: central; /* not supported by IE 11 */ +} + +marker path { + /* Safari and Chrome workaround for inheriting the style of its link. + Use any value that is larger than the length of the marker path. */ + stroke-dasharray: 50; +} + diff --git a/vowl_v2/data/webVOWLGraph.js b/vowl_v2/data/webVOWLGraph.js new file mode 100644 index 00000000..4eee46e0 --- /dev/null +++ b/vowl_v2/data/webVOWLGraph.js @@ -0,0 +1,1749 @@ +"use strict"; + +/*jshint devel:true*/ +/*global d3*/ + +/* ################ VARIABLES ################ */ +var GRAPH_WIDTH = window.innerWidth + , GRAPH_HEIGHT = window.innerHeight + , DEFAULT_VISIBLE_LINKDISTANCE = 160 + , visibleLinkDistance = DEFAULT_VISIBLE_LINKDISTANCE + , visibleLiteralLinkDistance = DEFAULT_VISIBLE_LINKDISTANCE + , CHARGE = -1000 + , LITERAL_HEIGHT = 20 + , LITERAL_WIDTH = 60 + , CLASS_RADIUS = 50 + , THING_RADIUS = 30 + , SPECIAL_OPERATIONS_RADIUS = 40 + , LABEL_HEIGHT = 28 + , LABEL_WIDTH = 80 + , ADDITIONAL_TEXT_SPACE = 4 + , CARDINALITY_HDISTANCE = 20 + , CARDINALITY_VDISTANCE = 10 + , SPACE_BETWEEN_SPANS = 12 + , force + , svg + , label + , link + , linkPath + , cardinalities + , node + , json + , lastFocusedNode + , curveFunction = d3.svg.line() + .x(function (d) { + return d.x; + }) + .y(function (d) { + return d.y; + }).interpolate("cardinal") + , loopFunction = d3.svg.line() + .x(function (d) { + return d.x; + }) + .y(function (d) { + return d.y; + }).interpolate("cardinal") + .tension(-1) + , zoom = d3.behavior.zoom() + .scaleExtent([0.1, 4]) + .on("zoom", zoomed); + + +/* ################################ STARTING GRAPH ################################ */ +function drawGraph(graphContainerElement, width, height) { + /* ################ SVG CONTAINER ################ */ + var graphContainer = d3.select(graphContainerElement).attr("id", "graph"); + + /* CUSTOMIZATION */ + if (width !== undefined) { + GRAPH_WIDTH = width; + } + + if (height !== undefined) { + GRAPH_HEIGHT = height; + } + + // Remove an existing graph + graphContainer.select(".svgGraph").remove(); + + svg = graphContainer + .append("svg") + .classed("svgGraph", true) + .attr("width", GRAPH_WIDTH) + .attr("height", GRAPH_HEIGHT) + .call(zoom) + .append("g"); + + graphOptions(); + + /* ################ FORCE LAYOUT ################ */ + + /* Initialize fields */ + initialize(); + + /* Creates the force layout with data from the json file */ + force = d3.layout.force() + .charge(getCharge()) + .distance(getLinkDistance) + .gravity(0.025) + .linkStrength(0.7) // Flexibility of links + .size([GRAPH_WIDTH, GRAPH_HEIGHT]) + .nodes(json.nodes) + .links(json.links) + .on("tick", tick) + .start(); + + /* Per-type markers, as they don't inherit styles */ + var defs = svg.append("defs"); + json.links.forEach(function (l, i) { + l.id = i; + if (!isSpecialLink(l)) { + addMarker(defs, l, false); + if (l.inverse) { + addMarker(defs, l, true); + } + } + }); + + /* ################ LINKS ################ */ + + /* Creates links groups */ + link = svg.selectAll(".link") + .data(json.links) + .enter().append("g") + .attr("class", function (d) { + return getMarkerId(d, true) + " " + getMarkerId(d, false); + }) + .classed("link", true); + /* Creates link paths */ + linkPath = link.append("path") + .attr("class", function (d) { + return d.type; + }) + .classed("link-path", true) + .attr("marker-end", function (l) { + if (!isSpecialLink(l)) { + return "url(#" + getMarkerId(l, false) + ")"; + } + return ""; + }) + .attr("marker-start", function (l) { + if (l.inverse && !isSpecialLink(l)) { + return "url(#" + getMarkerId(l, true) + ")"; + } + return ""; + }); + + + /* ################ LABELS ################ */ + + /* Creates label groups */ + label = svg.selectAll(".label") + .data(json.links) + .enter().append("g") + .classed("label", true); + + /* Exclude links without label */ + label = label.filter(function (d) { + var needsLabel = d.valueTo || d.valueFrom; + if (d.propertyTo === "disjoint") { + needsLabel = true; + } + return needsLabel; + }); + + /* First only add single labels */ + label.filter( + function (d) { + return !d.inverse; + }).each(function (d) { + addLabel(d3.select(this), d, "to"); + }); + + /* Then add double labels */ + label.filter( + function (d) { + return d.inverse; + }).each(function (d) { + addLabel(d3.select(this), d, "to"); + addLabel(d3.select(this), d, "from"); + }); + + + /* ############### CARDINALITIES ############### */ + + cardinalities = svg.selectAll(".cardinality") + .data(json.links).enter() + .append("g").classed("cardinality", true); + + cardinalities = cardinalities.filter(function (l) { + return l.cardTo || l.cardFrom; + }); + + cardinalities.filter( + function (l) { + return l.cardTo; + }).each(function () { + addCardinality(d3.select(this), "to"); + }); + + cardinalities.filter( + function (l) { + return l.cardFrom; + }).each(function () { + addCardinality(d3.select(this), "from"); + }); + + /* ################ NODES ################ */ + + var drag = d3.behavior.drag() + .on("dragstart", function (d) { + d3.event.sourceEvent.stopPropagation(); // Prevent panning + d.fixed = true; + }) + .on("drag", function (d) { + d.px = d3.event.x; + d.py = d3.event.y; + force.resume(); + }) + .on("dragend", function (d) { + d.fixed = false; + }); + + /* Creates node groups */ + node = svg.selectAll(".node") + .data(json.nodes) + .enter().append("g") + .attr("class", "node") + /*.on("click", function (d) { + if (d3.event.defaultPrevented) { + return; + } // ignore drag + // First remove all children vom
box and afterwards add new information + alert("Name: " + d.name + "\nType: " + d.type); + })*/ + .on("mouseover", function(d){ + if(d.linkIDs){ + d.linkIDs.forEach(function(entry){ + d3.select(link[0][entry]).select("path").classed("hovered", true); + }) + } + }) + .on("mouseout", function(d){ + if(d.linkIDs){ + d.linkIDs.forEach(function(entry){ + d3.select(link[0][entry]).select("path").classed("hovered", false); + }) + } + }) + .call(drag); + +// Adds the correct type to node. + node.each(function (d) { + var element = d3.select(this); + switch (d.type) { + case "class": + addClass(element, d); + break; + case "thing": + addThing(element, d); + break; + case "equivalent": + addEquivalentClass(element, d); + break; + case "deprecated": + addDeprecatedClass(element, d); + break; + case "external": + addExternalClass(element, d); + break; + case "literal": + addLiteral(element, d); + break; + case "datatype": + addDatatype(element, d); + break; + case "rdfsClass": + addRDFSClass(element, d); + break; + case "rdfsResource": + addRDFSResource(element, d); + break; + case "intersection": + addIntersectionClass(element, d); + break; + case "union": + addUnionClass(element, d); + break; + case "complement": + addComplementClass(element, d); + break; + default: + console.log("PROBLEM DURING DRAWING CLASSES - UNKNOWN TYPE: " + d.type); + } + }); + + /* ################ GET DETAILS ################ */ + getNodeInfo(); + getLinkInfo(); +} + +/* Calculates the new positions of the nodes and links */ +var tick = function tickFunct() { + + linkPath.attr("d", function (l) { + // Process self links in a separate function + if (l.source === l.target) { + return calculateSelfLinkPath(l); + } + + // Calculate these every time to get nicer curved arrows + var pathStart = calculateIntersection(l.target, l.source, 1) + , pathEnd = calculateIntersection(l.source, l.target, 1) + , curvePoint = calculateCurvePoint(pathStart, pathEnd, l); + l.curvePoint = curvePoint; + + return curveFunction([calculateIntersection(l.curvePoint, l.source, 1), + curvePoint, calculateIntersection(l.curvePoint, l.target, 1)]); + }); + + node.attr("transform", function (node) { + return "translate(" + node.x + "," + node.y + ")"; + }); + + cardinalities.selectAll("g").attr("transform", function (l) { + var group = d3.select(this) + , pos; + if (group.classed("to")) { + pos = calculateIntersection(l.curvePoint, l.source, CARDINALITY_HDISTANCE); + } else { + pos = calculateIntersection(l.curvePoint, l.target, CARDINALITY_HDISTANCE); + } + + var n = calculateNormalVector(l.curvePoint, l.source, CARDINALITY_VDISTANCE); + + if (l.source.index < l.target.index) { + n.x = -n.x; + n.y = -n.y; + } + + return "translate(" + (pos.x + n.x) + "," + (pos.y + n.y) + ")"; + }); + + label.selectAll("g").attr("transform", function (l) { + var group = d3.select(this) + , midX = l.curvePoint.x + , midY = l.curvePoint.y; + + if (l.inverse) { + if (group.classed("to")) { + midY += (LABEL_HEIGHT / 2 + 1); + } else if (group.classed("from")) { + midY -= (LABEL_HEIGHT / 2 + 1); + } + } + + return "translate(" + midX + "," + midY + ")"; + }); +}; + +/* ################ FUNCTIONS ################ */ + +/* Add String function to calculate the text field length */ +String.prototype.width = function (textStyle) { + // Set a default value + if (!textStyle) { + textStyle = "text"; + } + var d = d3.select("body") + .append("div") + .attr("class", textStyle) + .attr("id", "width-test") // tag this element to identify it + .text(this), + w = document.getElementById("width-test").offsetWidth; + d.remove(); + return w; +}; + +/* Function to truncate a string */ +String.prototype.truncate = function (maxLength, textStyle) { + maxLength -= ADDITIONAL_TEXT_SPACE; + if (isNaN(maxLength) || maxLength <= 0) { + return this; + } + + var text = this + , textLength = this.length + , textWidth + , ratio; + + while (true) { + textWidth = text.width(textStyle); + if (textWidth <= maxLength) { + break; + } + + ratio = textWidth / maxLength; + textLength = Math.floor(textLength / ratio); + text = text.substring(0, textLength); + } + + if (this.length > textLength) { + return this.substring(0, textLength - 3) + "..."; + } + return this; +}; + +/* Checks whether the passed node is a special node */ +var isSpecialLink = function isSpecialLinkFunct(link) { + if (link.type === "special") { + return true; + } + return false; +}; + +/* Reset zoom and pan properties */ +var resetGraph = function resetGraphFunct() { + zoom.translate([0, 0]).scale(1); + svg.attr("transform", "translate(" + zoom.translate() + ")scale(" + zoom.scale() + ")"); + if (linkDistanceClassSlider !== undefined) { + linkDistanceClassSlider.property("value", DEFAULT_VISIBLE_LINKDISTANCE); + } + if (linkDistanceLiteralSlider !== undefined) { + linkDistanceLiteralSlider.property("value", DEFAULT_VISIBLE_LINKDISTANCE); + } + changeDistance(); + // also reset additional details displayed + d3.select("#otherDetails").classed("hidden", true); +}; + +/* Initialize various fields */ +var initialize = function initializeFunct() { + for (var i = 0; i < json.nodes.length; i++) { + var node = json.nodes[i] + , maxTextWidth + , radius; + switch (node.type) { + case "deprecated": + case "external": + case "equivalent": + case "rdfsClass": + case "class": + radius = CLASS_RADIUS; + maxTextWidth = 2 * CLASS_RADIUS; + break; + case "union": + case "intersection": + case "complement": + radius = SPECIAL_OPERATIONS_RADIUS; + break; + case "rdfsResource": + case "thing": + radius = THING_RADIUS; + maxTextWidth = 2 * THING_RADIUS; + break; + case "literal": + case "datatype": + node.height = LITERAL_HEIGHT; + node.width = LITERAL_WIDTH; + maxTextWidth = LITERAL_WIDTH; + break; + } + node.maxTextWidth = maxTextWidth; + node.radius = radius; + } + + // Count multi edges and self links + json.links.forEach(function (link) { + var i = 0; + // Don't count multiple times the same source-target combination + if (isNaN(link.multiLinkCount)) { + var sameLinks = []; + + // Search all links with the source and target + json.links.forEach(function (otherLink) { + if ((link.source === otherLink.source && link.target === otherLink.target) || + (link.target === otherLink.source && link.source === otherLink.target)) { + sameLinks.push(otherLink); + } + }); + + // Set the total amount and its index for every node + for (i = 0; i < sameLinks.length; i++) { + sameLinks[i].multiLinkCount = sameLinks.length; + sameLinks[i].multiLinkIndex = i; + } + } + + if (isNaN(link.selfLinkCount)) { + var selfLinks = []; + + json.links.forEach(function (otherLink) { + if ((link.source === otherLink.source) && (link.target === otherLink.target)) { + selfLinks.push(otherLink); + } + }); + + for (i = 0; i < selfLinks.length; i++) { + selfLinks[i].selfLinkCount = selfLinks.length; + selfLinks[i].selfLinkIndex = i; + } + } + }); + + refreshSlider(); +}; + +/* Calculates the point where the link between the source and target node + * intersects the border of the target node */ +function calculateIntersection(source, target, additionalDistance) { + var dx = target.x - source.x + , dy = target.y - source.y + , innerDistance = target.radius; + + if (target.type === "literal" || + target.type === "datatype") { + var m_link = Math.abs(dy / dx) + , m_rect = target.height / target.width; + + if (m_link <= m_rect) { + var timesX = dx / (target.width / 2) + , rectY = dy / timesX; + innerDistance = Math.sqrt(Math.pow(target.width / 2, 2) + rectY * rectY); + } else { + var timesY = dy / (target.height / 2) + , rectX = dx / timesY; + innerDistance = Math.sqrt(Math.pow(target.height / 2, 2) + rectX * rectX); + } + } + + var length = Math.sqrt(dx * dx + dy * dy) + , ratio = (length - (innerDistance + additionalDistance)) / length + , x = dx * ratio + source.x + , y = dy * ratio + source.y; + + return {x: x, y: y}; +}; + +/* Adjusts the containers current scale and position */ +function zoomed() { + svg.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); +}; + +/* Calculate the visible link distance */ +var calculateLinkDistance = function calculateLinkDistanceFunct(l, visibleLinkDistance) { + var distance = visibleLinkDistance; + distance += l.target.radius; + distance += l.source.radius; + return distance; +}; + +/* Returns the link distance of the passed link */ +var getLinkDistance = function getLinkDistanceFunct(l) { + // Differentiate between class and literal nodes + if (l.source.type === "literal" || l.target.type === "literal" || + l.source.type === "datatype" || l.target.type === "datatype") { + return calculateLinkDistance(l, visibleLiteralLinkDistance) + } else { + return calculateLinkDistance(l, visibleLinkDistance) + } +}; + +/* Refreshs the slider */ +var refreshSlider = function refreshSliderFunct() { + if (linkDistanceClassSlider !== undefined) { + linkDistanceClassSlider.property("value", visibleLinkDistance); + } + if (linkDistanceClassLabel !== undefined) { + linkDistanceClassLabel.html(visibleLinkDistance); + } + if (linkDistanceLiteralSlider !== undefined) { + linkDistanceLiteralSlider.property("value", visibleLiteralLinkDistance); + } + if (linkDistanceLiteralLabel !== undefined) { + linkDistanceLiteralLabel.html(visibleLiteralLinkDistance); + } +}; + +/* Change linkDistance and charge */ +var changeDistance = function changeDistanceFunct() { + // Convert newDistance to int + visibleLinkDistance = +linkDistanceClassSlider.property("value"); + visibleLiteralLinkDistance = +linkDistanceLiteralSlider.property("value"); + + // Adjust charge and restart force layout + force.charge(getCharge()); + force.start(); + + refreshSlider(); +}; + +var getCharge = function getChargeFunct() { + var nodeCharge = (visibleLinkDistance / DEFAULT_VISIBLE_LINKDISTANCE) * CHARGE + , literalCharge = (visibleLiteralLinkDistance / DEFAULT_VISIBLE_LINKDISTANCE) * CHARGE; + return Math.min(nodeCharge, literalCharge); +}; + +/* Calculates the normal vector between two points */ +function calculateNormalVector(source, target, length) { + var dx = target.x - source.x + , dy = target.y - source.y + + , nx = -dy + , ny = dx + + , vlength = Math.sqrt(nx * nx + ny * ny) + , ratio = length / vlength; + + return {"x": nx * ratio, "y": ny * ratio}; +}; + +/* Calculates a point between two points for curves */ +function calculateCurvePoint(source, target, l) { + var distance = calculateMultiLinkDistance(l) + + // Find the center of the two points + , dx = target.x - source.x + , dy = target.y - source.y + + , cx = source.x + dx / 2 + , cy = source.y + dy / 2 + + , n = calculateNormalVector(source, target, distance); + + if (l.source.index < l.target.index) { + n.x = -n.x; + n.y = -n.y; + } + + if (l.multiLinkIndex % 2 !== 0) { + n.x = -n.x; + n.y = -n.y; + } + + return {"x": cx + n.x, "y": cy + n.y}; +}; + +/* Calculate the optimal Multi Link distance */ +function calculateMultiLinkDistance(l) { + var level = Math.floor((l.multiLinkIndex - l.multiLinkCount % 2) / 2) + 1 + , oddConstant = (l.multiLinkCount % 2) * 15 + , distance = 0; + switch (level) { + case 1: + distance = 20 + oddConstant; + break; + case 2: + distance = 45 + oddConstant; + break; + } + return distance * (visibleLinkDistance / DEFAULT_VISIBLE_LINKDISTANCE); +}; + +/* Calculates the radian of an angle */ +function calculateRadian(angle) { + angle = angle % 360; + if (angle < 0) { + angle = angle + 360; + } + var arc = (2 * Math.PI * angle) / 360; + if (arc < 0) { + arc = arc + (2 * Math.PI); + } + return arc; +}; + +/* Calculates links to itself and stores the point for the labels. Currently only working for circle nodes! */ +function calculateSelfLinkPath(l) { + var node = l.source + + , loopShiftAngle = 360 / l.selfLinkCount + , loopAngle = Math.min(60, loopShiftAngle * 0.8) + + , arcFrom = calculateRadian(loopShiftAngle * l.selfLinkIndex) + , arcTo = calculateRadian((loopShiftAngle * l.selfLinkIndex) + loopAngle) + + , x1 = Math.cos(arcFrom) * node.radius + , y1 = Math.sin(arcFrom) * node.radius + + , x2 = Math.cos(arcTo) * node.radius + , y2 = Math.sin(arcTo) * node.radius + + , fixPoint1 = {"x": node.x + x1, "y": node.y + y1} + , fixPoint2 = {"x": node.x + x2, "y": node.y + y2} + + , distanceMultiplier = 2.5 + , dx = ((x1 + x2) / 2) * distanceMultiplier + , dy = ((y1 + y2) / 2) * distanceMultiplier + , curvePoint = {"x": node.x + dx, "y": node.y + dy}; + l.curvePoint = curvePoint; + + return loopFunction([fixPoint1, curvePoint, fixPoint2]); +}; + +/* ################ MARKERS ################ */ + +/* Returns an id to get the marker to the matching link */ +function getMarkerId(l, inverse) { + return (l.type ? l.type : "normal") + l.id + (inverse ? "inverse" : ""); +}; + +/* Function that adds markers according to the used links */ +function addMarker(defs, link, inverse) { + defs.append("marker") + .attr("id", getMarkerId(link, inverse)) + .attr("viewBox", "0 -8 14 16") + .attr("refX", inverse ? 0 : 12) + .attr("refY", 0) + .attr("markerWidth", 12) // ArrowSize + .attr("markerHeight", 12) + .attr("markerUnits", "userSpaceOnUse") + .attr("orient", "auto") // Orientation of Arrow + .attr("class", (link.type ? link.type : "normal") + "Marker") + .append("path") + .attr("d", function () { + return inverse ? "M12,-8L0,0L12,8Z" : "M0,-8L12,0L0,8Z"; + }); +}; + +/* Methods to create hover effect for the specification */ +function labelMouseOver(tag) { + d3.selectAll("marker#" + tag) + .select("path") + .classed("hovered", true); + + d3.selectAll("." + tag) + .selectAll("path, text") + .classed("hovered", true); +}; +function labelMouseOut(tag) { + d3.selectAll("marker#" + tag) + .select("path") + .classed("hovered", false); + + d3.selectAll("." + tag) + .selectAll("path, text") + .classed("hovered", false); +}; +function indirectHighlightOn(tag) { + d3.selectAll("." + tag) + .selectAll("rect") + .classed("indirectHighlighting", true); +}; +function indirectHighlightOff(tag) { + d3.selectAll("." + tag) + .selectAll("rect") + .classed("indirectHighlighting", false); +}; + +/* Highlights the marker and link for the given label and direction */ +function labelMouseEnter(linkData, direction) { + var inverse = direction === "from"; + + d3.selectAll("marker#" + getMarkerId(linkData, inverse)) + .select("path").classed("hovered", true); + + d3.selectAll("." + getMarkerId(linkData, inverse)) + .selectAll("path, text") + .classed("hovered", true); + + svg.selectAll(".label").sort(function (a, b) { // select the parent and sort the path's + if (a.id === linkData.id && b.id !== linkData.id) { + return 1; // a is hovered + } else if (a.id !== linkData.id && b.id === linkData.id) { + return -1; // b is hovered + } else { + // workaround to make sorting in chrome for these elements stable + return a.id - b.id; // compare unique values + } + }); +}; + +/* Removes highlighting of marker and link for the given label and direction */ +function labelMouseLeave(linkData, direction) { + var inverse = direction === "from"; + d3.selectAll("marker#" + getMarkerId(linkData, inverse)) + .select("path").classed("hovered", false); + + d3.selectAll("." + getMarkerId(linkData, inverse)) + .selectAll("path, text").classed("hovered", false); +}; + +/* Function to add rectangles as label background */ +function addLabelRect(label, data, direction) { + label.append("rect") + .attr("class", function () { + var property = data.propertyTo; + if (direction === "from") { + property = data.propertyFrom; + } + return (property ? property : "object"); + }) + .classed("property", true) + .attr("x", -LABEL_WIDTH / 2) + .attr("y", -LABEL_HEIGHT / 2) + .attr("width", LABEL_WIDTH) + .attr("height", LABEL_HEIGHT) + .on("mouseenter", function (linkData) { + labelMouseEnter(linkData, direction); + highlightSubproperties(linkData, direction, true); + }) + .on("mouseleave", function (linkData) { + labelMouseLeave(linkData, direction); + highlightSubproperties(linkData, direction, false); + }); +}; + +/* Add the label to a link in the given direction */ +function addLabel(link, data, direction) { + var label = link.append("g") + .attr("id", "label" + data.id + direction) + .classed(direction, true); + + addLabelRect(label, data, direction); + if (data.propertyTo === "disjoint") { + addDisjointLabel(label); + return; + } + var labelText = label.append("text") + .classed("text", true) + .attr("text-anchor", "middle"); + + + addLabelText(labelText, data, direction); + addPropertyToLabel(labelText, data, direction); + addSubPropertyLabel(labelText, data, direction); +}; + +/* Adds a new to the label */ +function addLabelText(element, d, direction) { + element.append("tspan") + .attr("class", function () { + // If no type in any direction default class "text" + var classConst = ""; + + if (d.typeTo !== undefined || d.typeFrom !== undefined) { + classConst = classConst.concat("mainText"); + } else { + classConst = classConst.concat("text"); + } + + /* Adds additional classes according to the properties. */ + switch(d.propertyTo){ + case "external": + classConst = classConst.concat(" white"); + return classConst; + default: + } + + switch(d.propertyFrom){ + case "external": + classConst = classConst.concat(" white"); + return classConst; + default: + } + + return classConst; + }) + .text(function () { + var value; + if (direction === "to") { + value = d.valueTo; + } else if (direction === "from") { + value = d.valueFrom; + } else { + value = d.valueTo ? d.valueTo : d.valueFrom; + } + return value.toString().truncate(LABEL_WIDTH); + }); +}; + +/* Adds a new to the existing in the label position */ +function addPropertyToLabel(label, d, direction) { + var property; + if (direction === "to") { + if (!d.typeTo) { + return; + } + property = d.typeTo; + } else if (direction === "from") { + if (!d.typeFrom) { + return; + } + property = d.typeFrom; + } else { + var anyProperty = d.typeTo ? d.typeTo : d.typeFrom; + if (anyProperty) { + property = anyProperty; + } else { + return; + } + } + + // Insert the brackets at the beginning for receiving the correct length + var trimmedPropertyText = ")(" + property.toString().truncate(LABEL_WIDTH, "subtext"); + label.append("tspan") + .attr("x", 0).attr("y", 9) + .attr("class", "subtext") + .text("(" + trimmedPropertyText.substr(2) + ")"); +}; + +/* Adds a new to the existing in the label position */ +function addSubPropertyLabel(label, d, direction) { + var subProperty; + if (direction === "to") { + if (!d.equivPropTo) { + return; + } + subProperty = d.equivPropTo; + } else if (direction === "from") { + if (!d.subPropFrom) { + return; + } + subProperty = d.subPropFrom; + } else { + var anyProperty = d.equivPropTo ? d.equivPropTo : d.subPropFrom; + if (anyProperty) { + subProperty = anyProperty; + } else { + return; + } + } + + // Insert the brackets at the beginning for receiving the correct length + var trimmedPropertyText = "][" + subProperty.toString().truncate(LABEL_WIDTH, "subtext"); + label.append("tspan") + .attr("x", 0).attr("y", 9) + .attr("class", "subtext") + .text("[" + trimmedPropertyText.substr(2) + "]"); +}; + +function addDisjointLabel(label) { + label.append("circle") + .classed("symbol", true) + .classed("fineline", true) + .attr("cx", -12.5) + .attr("r", 10); + label.append("circle") + .classed("symbol", true) + .classed("fineline", true) + .attr("cx", 12.5) + .attr("r", 10); + + var text = label.append("text") + .classed("text", true) + .attr("text-anchor", "middle") + .attr("transform", "translate(0,20)"); + text.append("tspan") + .classed("subtext", true) + .text("(disjoint)"); +}; + +function addCardinality(link, direction) { + var card = link.append("g") + .attr("class", function (l) { + return getMarkerId(l, direction === "to"); + }) + .classed(direction, true); + + + card.append("text") + .classed("cardinality", true) + .attr("text-anchor", "middle") + .text(function (d) { + return direction === "to" ? d.cardTo : d.cardFrom; + }); +}; + +/* Adds a new line of text to the element. */ +function addTextline(element, word, additionalClass) { + if (element === undefined || word === undefined) { + return; + } + element.append("tspan") + .attr("class", additionalClass) + .classed("text", true) + .attr("x", 0) + .attr("y",function () { + return (element.property("childNodes").length - 1) * SPACE_BETWEEN_SPANS; + }).text(word); +} + +/* Adds a new line of text to the element. */ +function addSubTextNode(element, word, additionalClass) { + if (element === undefined || word === undefined) { + return; + } + element.append("tspan") + .attr("class", additionalClass) + .classed("text", true) + .classed("subtext", true) + .attr("x", 0) + .attr("y",function () { + return (element.property("childNodes").length - 1) * SPACE_BETWEEN_SPANS; + }).text(word); +}; + +/*Adds block to element. */ +function addTextBlock(element) { + element.append("text") + .classed("text", true) + .attr("text-anchor", "middle"); +}; + +/* Adds new literal. */ +function addLiteral(element, data) { + if (element === undefined) { + return; + } + + if (data !== undefined) { + element.append("rect") + .attr("class", data.type) + .classed("class", true) + .classed("special", true) + .attr("x", -LITERAL_WIDTH / 2) + .attr("y", -LITERAL_HEIGHT / 2) + .attr("width", LITERAL_WIDTH) + .attr("height", LITERAL_HEIGHT); + } else { + element.append("rect") + .attr("class", "literal") + .classed("class", true) + .attr("x", -LITERAL_WIDTH / 2) + .attr("y", -LITERAL_HEIGHT / 2) + .attr("width", LITERAL_WIDTH) + .attr("height", LITERAL_HEIGHT); + } + + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Literal"); + } +}; + +/* Adds new literal. */ +function addDatatype(element, data) { + if (element === undefined) { + return; + } + + if (data !== undefined) { + element.append("rect") + .attr("class", data.type) + .classed("class", true) + .attr("x", -LITERAL_WIDTH / 2) + .attr("y", -LITERAL_HEIGHT / 2) + .attr("width", LITERAL_WIDTH) + .attr("height", LITERAL_HEIGHT); + } else { + element.append("rect") + .attr("class", "datatype") + .classed("class", true) + .attr("x", -LITERAL_WIDTH / 2) + .attr("y", -LITERAL_HEIGHT / 2) + .attr("width", LITERAL_WIDTH) + .attr("height", LITERAL_HEIGHT); + } + + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Datatype"); + } +}; + +/* Appends thing node. */ +function addThing(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", "class") + .classed("white", true) + .classed("special", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "class") + .classed("white", true) + .classed("special", true) + .attr("r", THING_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Thing"); + } +}; + +/* Appends rdfs:Resource node. */ +function addRDFSResource(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", "class") + .classed("rdf", true) + .classed("special", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "class") + .classed("rdf", true) + .classed("special", true) + .attr("r", THING_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Resource"); + } +}; + +/* Appends class node. */ +function addClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", data.type) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "class") + .attr("r", CLASS_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Class"); + } +}; + +/* Appends rdfs:class node. */ +function addRDFSClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", "class") + .classed("rdf", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "rdf") + .classed("rdf", true) + .attr("r", CLASS_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Class"); + } +}; + + +/* Appends equivalentClass node. */ +function addEquivalentClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", "class white embedded") + .attr("r", data.radius); + element.append("circle") + .attr("class", "class") + .attr("r", function () { + return data.radius - 4; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "class") + .attr("r", CLASS_RADIUS - 4); + + element.append("circle") + .attr("class", "link") + .attr("r", CLASS_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + + var equivNames = data.equivalentClasses.map(function(node) {return node.name;}) + , equivNamesString = equivNames.join(", "); + addSubTextNode(element.select("text"), "[" + equivNamesString.truncate(data.maxTextWidth) + "]"); + } else { + addTextline(element.select("text"), "EquivalentClass"); + } + + // Center the complete textblock. + var rePositiony = (element.select("text").property("childElementCount") - 1) * SPACE_BETWEEN_SPANS / 2; + element.select("text").attr("transform", function () { + return "translate(0,-" + rePositiony + ")"; + }); +}; + +/* Appends externalClass node.*/ +function addExternalClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", data.type) + .classed("class", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "external") + .classed("class", true) + .attr("r", CLASS_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth), "white"); + } else { + addTextline(element.select("text"), "External", "white"); + } + addSubTextNode(element.select("text"), "(external)", "white"); + + // Center the complete textblock. + var rePositiony = (element.select("text").property("childElementCount") - 1) * SPACE_BETWEEN_SPANS / 2; + element.select("text").attr("transform", function () { + return "translate(0,-" + rePositiony + ")"; + }); +}; + +/* Appends deprecatedClass node.*/ +function addDeprecatedClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", data.type) + .classed("class", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "deprecated") + .classed("class", true) + .attr("r", CLASS_RADIUS); + } + // Adds text + addTextBlock(element); + if (data !== undefined) { + addTextline(element.select("text"), data.name.truncate(data.maxTextWidth)); + } else { + addTextline(element.select("text"), "Deprecated"); + } + addSubTextNode(element.select("text"), "(deprecated)"); + + // Center the complete textblock. + var rePositiony = (element.select("text").property("childElementCount") - 1) * SPACE_BETWEEN_SPANS / 2; + element.select("text").attr("transform", function () { + return "translate(0,-" + rePositiony + ")"; + }); +}; + +/* Appends intersectionClass node.*/ +function addIntersectionClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", data.type) + .classed("class", true) + .classed("special", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "intersection") + .classed("class", true) + .classed("special", true) + .attr("r", SPECIAL_OPERATIONS_RADIUS); + } + var symbol = element.append("g").classed("embedded", true); + + symbol.append("path") + .attr("class", "nostroke") + .classed("symbol", true).attr("d", "m 24.777,0.771 c0,16.387-13.607,23.435-19.191,23.832S-15.467,14.526-15.467,0.424S-1.216-24.4,5.437-24.4 C12.09-24.4,24.777-15.616,24.777,0.771z"); + symbol.append("circle") + .attr("class", "nofill") + .classed("fineline", true) + .attr("r", (SPECIAL_OPERATIONS_RADIUS - 15)); + symbol.append("circle") + .attr("cx", 10) + .attr("class", "nofill") + .classed("fineline", true) + .attr("r", (SPECIAL_OPERATIONS_RADIUS - 15)); + symbol.append("path") + .attr("class", "nofill") + .attr("d", "m 9,5 c 0,-2 0,-4 0,-6 0,0 0,0 0,0 0,0 0,-1.8 -1,-2.3 -0.7,-0.6 -1.7,-0.8 -2.9,-0.8 -1.2,0 -2,0 -3,0.8 -0.7,0.5 -1,1.4 -1,2.3 0,2 0,4 0,6"); + symbol.attr("transform", "translate(-" + (SPECIAL_OPERATIONS_RADIUS - 15) / 5 + ",-" + (SPECIAL_OPERATIONS_RADIUS - 15) / 100 + ")"); +}; + +/* Appends unionClass node.*/ +function addUnionClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", data.type) + .classed("class", true) + .classed("special", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "union") + .classed("class", true) + .classed("special", true) + .attr("r", SPECIAL_OPERATIONS_RADIUS); + } + var symbol = element.append("g") + .classed("embedded", true); + + symbol.append("circle") + .attr("class", "symbol") + .attr("r", (SPECIAL_OPERATIONS_RADIUS - 15)); + symbol.append("circle") + .attr("cx", 10) + .attr("class", "symbol") + .classed("fineline", true) + .attr("r", (SPECIAL_OPERATIONS_RADIUS - 15)); + symbol.append("circle") + .attr("class", "nofill") + .classed("fineline", true) + .attr("r", (SPECIAL_OPERATIONS_RADIUS - 15)); + symbol.append("path") + .attr("class", "link") + .attr("d", "m 1,-3 c 0,2 0,4 0,6 0,0 0,0 0,0 0,2 2,3 4,3 2,0 4,-1 4,-3 0,-2 0,-4 0,-6"); + symbol.attr("transform", "translate(-" + (SPECIAL_OPERATIONS_RADIUS - 15) / 5 + ",-" + (SPECIAL_OPERATIONS_RADIUS - 15) / 100 + ")"); +}; + +/* Appends complementClass node.*/ +function addComplementClass(element, data) { + if (element === undefined) { + return; + } + + // If element has data, normally in the force-directed graph. + if (data !== undefined) { + element.append("circle") + .attr("class", data.type) + .classed("class", true) + .classed("special", true) + .attr("r", function () { + return data.radius; + }); + } + // If no data exists, justs to make a prototype without functions. + else { + element.append("circle") + .attr("class", "complement") + .classed("class", true) + .classed("special", true) + .attr("r", SPECIAL_OPERATIONS_RADIUS); + } + var symbol = element.append("g").classed("embedded", true); + + symbol.append("circle") + .attr("class", "symbol") + .classed("fineline", true) + .attr("r", (SPECIAL_OPERATIONS_RADIUS - 15)); + symbol.append("path") + .attr("class", "nofill") + .attr("d", "m -7,-1.5 12,0 0,6"); + symbol.attr("transform", "translate(-" + (SPECIAL_OPERATIONS_RADIUS - 15) / 100 + ",-" + (SPECIAL_OPERATIONS_RADIUS - 15) / 100 + ")"); +}; + +/* Returns the type of the selected element, either node or label. */ +var getKindOfElement = function getKindOfElementFunct(element) { + if (element.classed("node")) { + return "node"; + } + + var theParent = element.node().parentNode; + if (theParent !== undefined && d3.select(theParent).classed("label")) { + return "label"; + } + + return undefined; +}; + +/* Toggles the highlighting of the given node. */ +var toggleNodeFocus = function toggleNodeFocusFunct(node) { + var firstChildElement = node.select("*") + , hasFocusClass = firstChildElement.classed("focused"); + + if (hasFocusClass) { + firstChildElement.classed("focused", false); + } else { + firstChildElement.classed("focused", true); + } +}; + +/* Toggles the highlighting of the given label. */ +var toggleLabelFocus = function toggleLabelFocusFunct(labelToHigh) { + var inverse = labelToHigh.classed("from") + , rectOfNode = labelToHigh.select("rect") + , notHasFocusClass = !rectOfNode.classed("focused"); + + rectOfNode.classed("focused", notHasFocusClass); + + d3.selectAll("marker#" + getMarkerId(labelToHigh.datum(), inverse)) + .select("path").classed("focused", notHasFocusClass); + + d3.selectAll("." + getMarkerId(labelToHigh.datum(), inverse)) + .selectAll("path, text") + .classed("focused", notHasFocusClass); +}; + +/* Sets focus on the clicked element. */ +var focusOnElement = function focusOnElementFunct(element) { + var lastFocusedElement + , currentNode = element.node(); + + // Remove highlighting of last element if exists. + if (lastFocusedNode !== undefined) { + lastFocusedElement = d3.select(lastFocusedNode); + var kindOfLastElement = getKindOfElement(lastFocusedElement); + + if (kindOfLastElement === "node") { + toggleNodeFocus(lastFocusedElement); + } else if (kindOfLastElement === "label") { + toggleLabelFocus(lastFocusedElement); + } + } + + // If the same element was clicked before, not highlighting again. + if (lastFocusedNode === currentNode) { + hideInfoField(); + lastFocusedNode = undefined; + return; + } + lastFocusedNode = currentNode; + + var kindOfThisElement = getKindOfElement(element); + + if (kindOfThisElement === "node") { + toggleNodeFocus(element); + } else if (kindOfThisElement === "label") { + toggleLabelFocus(element); + } +}; + +var getNodeInfo = function getNodeInfoFunct() { + var node = svg.selectAll(".node") + .on("click", function(d) + { + d3.select("#otherDetails").classed("hidden", false); + d3.select("#class").classed("hidden", false); + d3.select("#prop").classed("hidden", true); + + setUriLabel(d3.select("#name"), d.name, d.uri); + + var equivUriSpan = d3.select("#classEquivUri"); + + if (equivUriSpan.node() === null) { + /* + Do absolutely nothing -- this is for specVOWL.js + Otherwise typeError null + */ + } else { + var equivUriSpanParent = d3.select(equivUriSpan.node().parentNode); + if (d.equivalentClasses !== undefined) { + listUriLabels(equivUriSpan, d.equivalentClasses); + equivUriSpanParent.classed("hidden", false); + } else { + equivUriSpanParent.classed("hidden", true); + } + } + d3.select("#typeNode").text(getTypeNode(d.type)); + + var disjointNodes = d3.select("#disjointNodes"); + if (equivUriSpan.node() === null) { + /* + Do absolutely nothing -- this is for specVOWL.js + Otherwise typeError null + */ + } else { + var disjointNodesParent = d3.select(disjointNodes.node().parentNode); + if (d.disjoints !== undefined) { + listUriLabels(disjointNodes, d.disjoints); + disjointNodesParent.classed("hidden", false); + } else { + disjointNodesParent.classed("hidden", true); + } + } + + focusOnElement(d3.select(this)); + }); +}; + +/* Sets a listing of uri labels of the passed array of nodes */ +var listUriLabels = function listUriLabelsFunct(element, nodes) { + element.selectAll("*").remove(); + nodes.forEach(function (node, index) { + if (index > 0) { + element.append("span").text(", "); + } + appendUriLabel(element, node.name, node.uri); + }); +}; + +/* Removes all existing child elements and appends an uri label */ +var setUriLabel = function setUriLabelFunct(element, name, uri) { + element.selectAll("*").remove(); + appendUriLabel(element, name, uri) +}; + +/* Appends a field containing the name and if existing a hyperlink to the set uri */ +var appendUriLabel = function appendUriLabelFunct(element, name, uri) { + var tag; + if (uri) { + tag = element.append("a").attr("href", uri); + } else { + tag = element.append("span"); + } + tag.text(name); +}; + +var getTypeNode = function(type) { + switch(type) { + case "class": + return "OWL Class"; + case "thing": + return "Thing"; + case "external": + return "External Class"; + case "equivalent": + return "Equivalent Class"; + case "deprecated": + return "Deprecated Class"; + case "rdfsClass": + return "RDFS Class"; + case "rdfsResource": + return "RDFS Resource"; + case "literal": + return "Literal"; + case "datatype": + return "Datatype"; + case "union": + return "Union Of"; + case "intersection": + return "Intersection Of"; + case "complement": + return "Complement Of"; + } +}; + +var getTypeLink = function(type) { + switch(type) { + case "object": + return "Object Property"; + case "datatype": + return "Datatype Property"; + case "rdf": + return "RDF Property"; + case "deprecated": + return "Deprecated Property"; + case "external": + return "External Property"; + case "disjoint": + return "Disjoint With"; + case "subclass": + return "Subclass of"; + default: + return "Object Property"; + } +}; + +var getLinkInfo = function getLinkInfoFunct() { + /* We have to separate "from" labels by their class, because the stored data + is the data of the link which is identical in both directions */ + svg.selectAll(".label .from") + .on("click", function(l) + { + hideNodeInfoFields(); + setUriLabel(d3.select("#propname"), l.valueFrom, l.uriFrom); + d3.select("#typeProp").text(getTypeLink(l.propertyFrom)); + + if (l.inverse === true) { + d3.select("#inverse").style("display","block"); + setUriLabel(d3.select("#inverse span"), l.valueTo, l.uriTo); + } else { + d3.select("#inverse").style("display","none"); + } + if (l.cardTo !== undefined) { + d3.select("#minCardinality").style("display","block"); + d3.select("#minCardinality span").text(l.cardFrom); + } else { + d3.select("#minCardinality").style("display","none"); + } + if (l.cardFrom !== undefined) { + d3.select("#maxCardinality").style("display","block"); + d3.select("#maxCardinality span").text(l.cardTo); + } else { + d3.select("#maxCardinality").style("display","none"); + } + //d3.select("#inverse").text(l.valueTo); + setUriLabel(d3.select("#domain"), l.target.name, l.target.uri); + setUriLabel(d3.select("#range"), l.source.name, l.source.uri); + + focusOnElement(d3.select(this)); + }); + + svg.selectAll(".label .to") + .on("click", function(l) + { + hideNodeInfoFields(); + setUriLabel(d3.select("#propname"), l.valueTo, l.uriTo); + d3.select("#typeProp").text(getTypeLink(l.propertyTo)); + + if (l.inverse === true) { + d3.select("#inverse").style("display","block"); + setUriLabel(d3.select("#inverse span"), l.valueFrom, l.uriFrom); + } else { + d3.select("#inverse").style("display","none"); + } + if (l.cardTo !== undefined) { + d3.select("#minCardinality").style("display","block"); + d3.select("#minCardinality span").text(l.cardTo); + } else { + d3.select("#minCardinality").style("display","none"); + } + if (l.cardFrom !== undefined) { + d3.select("#maxCardinality").style("display","block"); + d3.select("#maxCardinality span").text(l.cardFrom); + } else { + d3.select("#maxCardinality").style("display","none"); + } + + setUriLabel(d3.select("#domain"), l.source.name, l.source.uri); + setUriLabel(d3.select("#range"), l.target.name, l.target.uri); + + focusOnElement(d3.select(this)); + }); +}; + +/* Highlights related subproperties if they are set */ +var highlightSubproperties = function highlightSubpropertiesFunct(link, direction, classed) { + var subproperties = link.subpropertiesTo; + + if (direction === "from") { + subproperties = link.subpropertiesFrom; + } + + if (subproperties === undefined) { + return; + } + + subproperties.forEach(function(l) { + d3.select("#label" + l.id + (l.direction ? l.direction : "to")) + .select("rect") + .classed("indirectHighlighting", classed); + }); +}; + +var hideNodeInfoFields = function hideNodeInfoFieldsFunct() { + d3.select("#otherDetails").classed("hidden", false); + d3.select("#prop").classed("hidden", false); + d3.select("#class").classed("hidden", true); +}; + +var hideInfoField = function hideNodeInfoFieldsFunct() { + d3.select("#otherDetails").classed("hidden", true); +}; + +function refreshOntology(jsonFile) { + clearCanvas(); + jsonURI = jsonFile; + loadGraph(); +}; + +var clearCanvas = function clearCanvasFunct() { + var graphTag = document.getElementById('graph') + , svg = graphTag.getElementsByTagName("svg")[0]; + d3.select(svg).remove(); + d3.select(reset).remove(); + d3.selectAll(".slideOption > *").remove(); + hideInfoField(); + zoom.translate([0, 0]).scale(1); +}; diff --git a/vowl_v2/index.html b/vowl_v2/index.html new file mode 100644 index 00000000..be79aa7e --- /dev/null +++ b/vowl_v2/index.html @@ -0,0 +1,1260 @@ + + + + + + + + + + +VOWL: Visual Notation for OWL Ontologies + + + +
+
+

VOWL: Visual Notation for OWL Ontologies

+

Specification of Version 2.0 – 7 April 2014

+
+
+
This version:
+
http://purl.org/vowl/spec/v2/
+
Latest version
+
http://purl.org/vowl/spec/
+
Previous version:
+
http://purl.org/vowl/spec/v1/
+
Authors:
+
Stefan Negru, Alexandru Ioan Cuza University
+ Steffen Lohmann, University of Stuttgart
+ Florian Haag, University of Stuttgart
+
+
+ visualdataweb.org »
+
+
+

Abstract

+

The Visual Notation for OWL Ontologies (VOWL) defines a visual +language for the user-oriented representation of ontologies. It provides + graphical depictions for elements of the Web Ontology Language (OWL) +that are combined to a force-directed graph layout visualizing the +ontology.

+

This specification focuses on the visualization of the ontology +schema (i.e. the classes, properties and datatypes, sometimes called +TBox), while it also includes recommendations on how to depict +individuals and data values (the ABox). Familiarity with OWL and other Semantic Web technologies is required to understand this specification.

+
+
+
+

Table of Contents

+
    +
  1. Overview
  2. +
  3. Basic Building Blocks
  4. +
  5. Visual Notation
  6. +
  7. Example
  8. +
  9. Acknowledgments
  10. +
  11. References
  12. +
+
+
+
+

Overview [back to top]

+

The Visual Notation for OWL Ontologies (VOWL) is based on only a handful of graphical primitives + forming the alphabet of the visual language: Classes are depicted as +circles that are connected by lines and arrows representing the property + relations. Property labels and datatypes are shown in rectangles. +Information on individuals and data values is either displayed in the +visualization itself or in another part of the user interface.

+

The second ingredient of VOWL is a color scheme + complementing the graphical primitives. It defines colors for the +visual elements to allow for an easy distinction of different types of +classes and properties. Although the color scheme is defined in an +abstract way leaving room for customization, a set of concrete color +recommendations provides guidance for developers.

+

Finally, the visual elements are combined to a graph that is +rendered in a force-directed layout and represents the ontology. VOWL +defines splitting rules to specify which elements are multiplied and thus displayed several times in the visualization to improve the overall layout.

+

VOWL can be used with any version of OWL (i.e. OWL 1 and OWL 2), + although not all language constructs (especially of OWL 2) are included + in this specification. Best results may be achieved with OWL DL or the more restrictive profiles OWL 2 EL/QL/RL, as well as OWL Lite. VOWL also provides graphical depictions for elements of RDF and RDFS that are reused in OWL, such as rdf:Property or rdfs:subClassOf.

+
+
+
+

Basic Building Blocks [back to top]

+

This section introduces the graphical primitives and color scheme that form the basic building blocks of VOWL. It also defines splitting rules for elements in the graph visualization and gives some general guidelines for using the notation.

+

Graphical Primitives

+

Table 1 lists all graphical primitives used in VOWL.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 1. Graphical primitives. +
NamePrimitiveDescriptionApplication
Circle + +

Each circle represents a class of the ontology. The +color of the circle depends on the type of class. There is an +implementation-specific default size for circles.

+

If an ontology contains individuals and unless purely the + schema (i.e. the TBox) is considered, the circle can become larger than + the default size – in that case, its size corresponds to the number of +individuals that are instances of the class. VOWL does not specify a +particular function for mapping the number of individuals to the circle +size – good results may be achieved with a logarithmic or square-root +scaling in most cases. A maximum size may be imposed. + Individuals inferred from subclasses are counted as well +if reasoning is available and not deactivated.

+

The circles representing the special classes owl:Thing and rdfs:Resource + are exceptions. They are not scaled but have a fixed size that is +smaller than the default size of classes. In addition, the circles of +these two classes have a dashed border and are multiplied in the +visualization according to the splitting rules.

owl:Class, rdfs:Class, owl:DeprecatedClass, owl:Thing, rdfs:Resource
Line + + +

Lines are used to represent property relations. They usually have an arrowhead indicating the direction of the relation. The line style and arrowhead + to use are determined by the type of the property. If the same two +classes are connected by multiple lines (i.e. if there are multi-edges +between circle nodes in the graph visualization), the lines may be +curved.

rdfs:domain, rdfs:range, owl:disjointWith, rdfs:subClassOf, owl:unionOf, owl:intersectionOf, owl:complementOf
Arrowhead + + +

Arrowheads indicate the direction of property relations + by pointing to the object of the property – i.e., a datatype, class, or + class instance that is defined as the range of that property.

+

Arrowheads representing range axioms are filled with the foreground color; arrowheads representing subclass relations are filled with the neutral color.

rdfs:range (with foreground color), rdfs:subClassOf (with neutral color)

Rectangle + +

Property labels and datatypes are shown in rectangles. If representing datatypes, the rectangles have the datatype color and a border. If representing property labels, they are borderless and colored according to the property type.

rdfs:Datatype, rdfs:Literal, property labels

Line style + + +

The lines and borders of some types of classes and +properties are dashed or dotted. A dashed line indicates set operators +and class disjointness (if visualized). A dashed border indicates literals and special types of classes. A dotted line is reserved for subclass relations.

dotted line: rdfs:subClassOf;
+ dashed line: owl:disjointWith, owl:unionOf, owl:intersectionOf, owl:ComplementOf;
+ dashed border: owl:Thing, rdfs:Resource, rdfs:Literal, and anonymous classes (as part of set operators)

Text + + text + number + symbol + +

Text is used for labels and type information, numbers +represent cardinalities and symbols may complement schematic +illustrations. Moreover, an infobox with textual + information from the ontology header, such as the title and description + of the ontology, may be displayed in the visualization.

rdfs:label, type of property ("Subclass of" for rdfs:subClassOf), + additional type information in brackets (e.g. "deprecated", +"functional", etc.), symbols in schematic illustrations (e.g. union +symbol ("∪") for owl:unionOf), cardinalities, infobox

+

Color Scheme

+

Table 2 lists the colors used in VOWL. +They are defined in an abstract way, along with a description and a +recommendation for a concrete color, including its hex code. Developers +may choose different colors, as long as they comply with the abstract +descriptions. All colors are defined relative to the canvas color, + which is assumed to be very light. The colors (and color descriptions) +may be 'inverted' if the visualization is presented on a dark +background.

+

While the colors ease the reading of the visualization, they are +not required to understand it. The visualization is also understandable +if printed in black and white or read by color-blind people, though some + details may not be visible any longer (e.g. if a class is of type owl:Class or rdfs:Class). + If these details should also be available in black and white prints of +the visualization, they may be added as text (e.g. in the label of the +element).

+

There may be conflicts in using this +color scheme, e.g. when a deprecated class belongs to an external +ontology. They should be resolved by giving one of the colors a higher +priority and adding all information in the label and/or another part of +the user interface (e.g. a sidebar). Recommendations are given in the general guidelines.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 2. Color scheme. +
Abstract color nameConcrete color recommendationDescriptionApplication
Canvas#fffwhite

Very light color with a good contrast to all other colors.

background of the visualization

Neutral#fffwhite

Light color with a good contrast to all other colors (usually similar or identical to the canvas color).

owl:Thing, arrowhead of rdfs:subClassOf, double border of owl:equivalentClass

Foreground#000black

Very dark color with a good contrast to all other colors, except the external color.

lines, borders, arrowheads, text, numbers, symbols

General#acflight blue

Light color with a good contrast to the foreground color.

owl:Class, owl:ObjectProperty (incl. subclasses), owl:disjointWith

Rdf#c9clight purple

Color similar to the general color with a good contrast to the foreground color.

rdfs:Class, rdfs:Resource, rdf:Property

Deprecated#ccclight gray

Color that is clearly different from the other colors and that is associated with being 'deactivated'.

owl:DeprecatedClass, owl:DeprecatedProperty

External#36cdark blue

Dark version of the general color, with the text in the neutral color instead of the foreground color.

Classes and properties from other ontologies that are linked in the ontology being visualized.

Datatype#fc3yellow

Light color that is clearly different from the other colors.

rdfs:Datatype, rdfs:Literal

Datatype Property#9c6light green

Light color that is clearly different from the other colors.

owl:DatatypeProperty

Graphics#69cmedium blue

Darkened version of the general color.

Schematic illustrations in owl:disjointWith, owl:unionOf, owl:intersectionOf, owl:ComplementOf

Highlighting#f00red

Very visible color, clearly indicating that an element is hovered or selected.

circles, rectangles, lines, borders, arrowheads

Indirect Highlighting#f90orange

Color similar to the highlighting color.

rectangles, circles

+

Splitting Rules

+

While some generic elements do not carry important domain information (e.g. owl:Thing, rdfs:Literal), + they may be connected to a lot of other elements in the ontology. This +would result in many links in the graph visualization that could +negatively affect its layout and readability. In addition, these highly +connected elements would tend to stand out among the other elements, +giving them visual emphasis that does not adequately reflect their +importance in the ontology. Therefore, VOWL defines splitting rules for +some generic OWL elements.

+

Table 3 lists the two different splitting rules, along with the OWL elements they are applied to.

+ + + + + + + + + + + + + + + + + + + + + +
+ Table 3. Splitting rules. +
NameDescriptionApplication
Splitting by property

The element is visualized once for every property it is linked to, i.e. if an element is linked to m properties, it is represented m times.

rdfs:Datatype, rdfs:Literal

Splitting by class

The element is visualized once for every class it is linked to (via property relations), i.e. if an element is linked to n classes, it is represented n times – independently of how often the element is linked to each class.

owl:Thing, rdfs:Resource

+

Note that each link of a splitted element is connected to only one of its representations in the graph visualization, not to all of them. Also note the other VOWL guidelines for the visualization of owl:Thing.

+

Elements that are defined to be equivalent (using owl:equivalentProperty or owl:equivalentClass) are, on the contrary, represented by only one visual element in the graph.

+
+

General Guidelines

+

Some general guidelines and recommendations for the usage and implementation of VOWL are listed in the following:

+

Labels

+

If elements do not have an rdfs:label, + it is recommended to take the last part of the URI as label, i.e. the +part that follows the last slash (/) or hash (#) character. Labels may +be abbreviated if they do not fit in the available space (e.g. +"Winnie-the-Pooh" → "Winnie…"). The full label should be shown on demand + in these cases (e.g. in a tooltip or sidebar).

+

Graph Layout

+

The visual elements are combined to a graph that should be +rendered in an appealing and readable layout. The positions of the +circles should be roughly determined by the number of inbound and +outbound property relations, i.e. the more property relations a class +has, the more centric its circle representation in the layout. It is +recommended to use a force-directed graph layout (though other layouts +may be equally or even more appropriate in certain cases). The users +should be enabled to adapt the graph layout (e.g. by repositioning the +nodes that represent the classes and datatypes).

+

Missing Domain and/or Range Information

+

If no domain and/or range axiom is defined for a property, owl:Thing should be used as domain and/or range. An exception are datatype properties without a defined range, where rdfs:Literal is used as range instead.

+

Visualization of owl:Thing

+

The visual representation of owl:Thing should only be used if either no domain and/or range axiom is defined for a property, or if owl:Thing is explicitly defined as domain and/or range. It is not recommended to visualize subclass relations of owl:Thing, as every user-defined class is implicitly a subclass of owl:Thing and the subclass relations would unnecessarily clutter the visualization.

+

External Elements

+

Elements whose base URI differs from that of the visualized +ontology may be marked as external (this feature is optional). +Developers may define different colors to visually group external +elements by their base URI, as long as they use the representation with +'inverted coloring' (i.e. dark color with light font) defined for +external elements (i.e. external classes and external properties).

+

Interactive Highlighting

+

The interactive highlighting assists in the visual exploration of + the ontology by indicating hovered, selected, and related elements. +Three modes of interactive highlighting are distinguished, two of which +are direct:

+
    +
  1. Highlight on hover: changes the fill color of the hovered element (plus the color of the line and arrow if any) to the highlighting color. This highlighting mode is dependent on the interaction context (e.g., it may not be supported by many touch interfaces).
  2. +
  3. Highlight on selection: changes the border color of the selected element (plus the color of the line and arrow if any) to the highlighting color. Note that it should also be possible to deselect elements that have been selected.
  4. +
  5. The third highlighting mode is +indirect. It expresses some kind of relationship between elements +without connecting them by a line. It is used to interactively indicate +sub- and superproperties of a hovered property. Like the highlight on hover, + it changes the fill color of the element (though not necessarily the +color of the line and arrow if any), but this time to the indirect highlighting color.
  6. +
+

Conflicts

+

The deprecated color has priority over the external color, i.e. if a class or property from an external ontology is deprecated, it should be visualized in the deprecated color. + In such cases, the type information displayed in brackets will include +all information in a comma-separated form (e.g. "deprecated, external"). + If a property is symmetric and functional, the type information should +be "symmetric, functional" accordingly.

+
+
+
+

Visual Notation [back to top]

+

The following tables list the graphical representations for the +different OWL elements (and some RDF and RDFS elements reused by OWL). +They are provided as interactive Scalable Vector Graphics (SVG) and implement the highlight on hover effects.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 4. Graphical representations of classes. +
Ontology elementGraphical representationDescription
owl:Class + + + Class + +

Circle in general color showing the class label in the selected language.

rdfs:Class + + + Class + +

Class representation in rdf color.

External class
+ (different base URI)
+ + + + Class + (external) + + +

Class representation in external color and with indication "external" in brackets (same representation for external owl:Class and rdfs:Class).

owl:DeprecatedClass + + + + Class + (deprecated) + + +

Class representation in deprecated color and with indication "deprecated" in brackets (same representation for deprecated owl:Class and rdfs:Class). + This graphical representation is also used for deprecated external +classes, with indication "deprecated, external" in brackets.

owl:Thing
+ (owl:Nothing)
+ + + Thing + +

Smaller circle in neutral color with a dashed border and label "Thing". This graphical representation is multiplied in the visualization according to the splitting rules. The same representation with label "Nothing" may be used to represent owl:Nothing (though it is generally not recommended to include owl:Nothing in the visualization at all).

rdfs:Resource + + + Resource + +

Smaller circle in rdf color with a dashed border and label "Resource". This graphical representation is multiplied in the visualization according to the splitting rules.

+

Note that the text string "Class" is used as a placeholder for the actual class label + in the graphical representations. In contrast, the text strings in +brackets (i.e. "external" and "deprecated") and the labels "Thing" and +"Resource" are not placeholders but literally shown in the +visualization.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 5. Graphical representations of properties. +
Ontology elementGraphical representationDescription
rdfs:domain, rdfs:range + + + Class A + + + + + + + + Class B + +

Solid line starting at the domain with an arrowhead in the foreground color + that points to the range. This graphical representation does never +occur on its own but always in combination with the property for which +the domain and range have been defined (missing domain or range information is replaced).

owl:ObjectProperty + + + Class A + + + + + + + + ObjectProperty + + + + Class B + +

Property representation showing the property label in a rectangle having the general color.

owl:DatatypeProperty + + + Class A + + + + + + + + DatatypeProperty + + + + Datatype + +

Property representation showing the property label in a rectangle having the datatype property color .

rdf:Property + + + Class A + + + + + + + + Property + + + + Class B + +

Property representation showing the property label in a rectangle having the rdf color.

External property
+ (different base URI)
+ + + Class A + + + + + + + + Property + + + + + Class B + +

Property representation showing the property label in a rectangle having the external color (same representation for external owl:ObjectProperty, owl:DatatypeProperty, and rdf:Property).

owl:DeprecatedProperty + + + Class A + + + + + + + + DeprecatedProperty + + + + Class B + +

Property representation showing the property label in a rectangle having the deprecated color (same representation for deprecated owl:ObjectProperty, owl:DatatypeProperty, rdf:Property, and external properties.)

owl:FunctionalProperty + + + Class A + + + + + + + + + Property + (functional) + + + + + Class B + +

Property representation with indication "functional" +in brackets. The color of the rectangle depends on the type of property, + i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

+

The global cardinality constraint of functional +properties is not made explicit in the visualization to avoid any +confusion with cardinality constraints defined with owl:cardinality, owl:minCardinality, and owl:maxCardinality that are displayed in the visualization.

owl:InverseFunctionalProperty + + + Class A + + + + + + + + + ObjectProperty + (inverse functional) + + + + + Class B + +

Object property representation with indication "inverse + functional" in brackets. The global cardinality constraint of inverse +functional properties is not made explicit in the visualization for the +same reason as for functional properties.

owl:TransitiveProperty + + + Class A + + + + + + + + + ObjectProperty + (transitive) + + + + + Class B + +

Object property representation with indication "transitive" in brackets.

Properties with identical domain and range + + + + + + + Class A + + + + ObjectProperty + +

Object property representation with the line starting and ending at the same class representation (reflexive property representation). + If there are several of these properties, their representations should +be placed around the circle in a way that maintains readability.

owl:SymmetricProperty + + + + + + + Class A + + + + + ObjectProperty + (symmetric) + + +

Reflexive property representation with indication "symmetric" in brackets.

+

Note that the text strings "Property", "ObjectProperty", +"DatatypeProperty", and "DeprecatedProperty" are used as placeholders +for the actual property labels in the graphical +representations. In contrast, the text strings in brackets (i.e. +"functional", "inverse functional", "transitive", and "symmetric") are +not placeholders but literally shown in the visualization.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 6. Graphical representations of further properties. +
Ontology elementGraphical representationDescription
owl:cardinality,
+ owl:minCardinality, owl:maxCardinality
+ + + Class A + + + + + + + + Property + + + + x..y + + + + + Class B + +

Exact, minimal, and maximal cardinality constraints +are written as numbers near the end of the property arrow. The +representation is similar to the UML notation for cardinalities, + i.e. the letters "x" and "y" in the example represent the minimum and +maximum cardinality for that property. Exact cardinalities are +represented by only one number, while the asterisk (*) denotes an +unrestricted cardinality. Examples are "0..1" for a cardinality of 0 to +1, "1..*" for a minimum cardinality of 1, or "3" for a cardinality of +exactly 3.

+

The default cardinality of most properties is any number + (i.e. zero or more) and would be represented by a sole asterisk. +However, it is recommended to only depict cardinalities that are +explicitly specified with owl:cardinality, owl:minCardinality, and owl:maxCardinality. Default property cardinalities (incl. the global cardinality constraints of functional and inverse functional properties) are better not shown in the visualization to avoid confusion and reduce visual clutter.

+

The color of the rectangle depends on the type of property, i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

owl:disjointWith + + + Class A + + + + + + + + + + + + + (disjoint) + + + + + Class B + +

Dashed line without arrowhead connecting the disjoint +classes, accompanied by a Venn diagram illustration of two disjoint +sets. The illustration has the graphics color and is shown in a rectangle colored in the general color, along with the indication "disjoint" in brackets.

+

If several classes are pairwise disjoint, this could be +visualized by connecting each two of them. As an alternative to showing +this element in the visualization, owl:disjointWith + statements may be presented as details on demand in another part of the + user interface, which is recommended since it usually results in a less + cluttered graph.

rdfs:subClassOf + + + Class A + + + + + + + + Subclass of + + + + Class B + +

Dotted line starting at the subclass with an arrowhead filled with the neutral color that points to the superclass. The representation is similar to the UML notation for generalizations + but with a dashed line instead of a solid one to make it clearly +distinguishable from other property relations. In addition, it is +recommended to add the label "Subclass of" to the representation to +clarify the semantics of the relation. The label has either a +transparent background (unless highlighted) or is shown in a rectangle +that has the neutral color, which is recommended.

rdfs:subPropertyOf + + + + + + + + + + + Class A + + + + + Property + + + + Subproperty + + + + + Class B + +

If a property is hovered, its sub- and superproperties (if any) may be dynamically highlighted using the indirect highligthing color and mode. + The color of the rectangle depends on the type of property, i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

owl:inverseOf + + + Class A + + + + + + + + + + + + + + ObjectProperty + + + + InverseProperty + + + + + Class B + +

Object property representation with arrowheads at both +ends, annotated with the label of the property and its inverse +counterpart (interactive highlighting of direction). In order to +indicate which label denotes which direction in non-interactive +contexts, each label may be slightly displaced toward its respective +arrowhead (not shown in the example).

owl:equivalentProperty + + + Class A + + + + + + + + + Property A + [Property B] + + + + + Class B + +

This graphical representation is used for two or more properties that are defined to be equivalent. One of the property labels is the main label, while the rest is listed in square brackets (abbreviated if they do not all fit). The main label is taken from a property with the same base URI as the ontology. If there is no such property (i.e. all properties are external), it is taken from any of the properties.

+

The color of the rectangle depends on the type of property from which the main label is taken, i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

owl:equivalentClass + + + + + Class A + [Class B] + + +

Class representation with a double border. The space between the two borders has the neutral color. This graphical representation is used for two or more classes that are defined to be equivalent. One of the class labels is the main label, while the rest is listed in square brackets (abbreviated if they do not all fit). The main label is taken from a class with the same base URI as the ontology. If there is no such class (i.e. all classes are external), + it is taken from any of the classes. Note that the graphical +representation has always a double border, independently of how many +classes it represents.

+

The color of the circle depends on the type of class from which the main label is taken, i.e. general color = owl:Class, datatype property color = rdfs:Class, external color = external class, and deprecated color = owl:deprecatedClass.

+

The graphical representations of equivalent classes may also be used to represent owl:sameAs relations that can be defined between classes in OWL Full.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 7. Graphical representations of set operators. +
Ontology elementGraphical representationDescription
owl:unionOf + + + Class A + + + + + + + + + + + + + + + + + + + Class B + +

Class representation with a dashed border and a Venn diagram of two united sets colored in the graphics color. The circle represents the anonymous class of the owl:unionOf + statement, which is additionally indicated by the union symbol ("∪") +used as a label. The anonymous class is connected to the classes it is +composed of by a dashed line (without arrowhead).

owl:intersectionOf + + + Class A + + + + + + + + + + + + + + + + + + + Class B + +

Class representation with a dashed border and a Venn diagram of two intersected sets colored in the graphics color. The circle represents the anonymous class of the owl:intersectionOf + statement, which is additionally indicated by the intersection symbol +("∩") used as a label. The anonymous class is connected to the classes +it is composed of by a dashed line (without arrowhead).

owl:complementOf + + + Class + + + + + + + + + + + +

Class representation with a dashed border containing a smaller circle in the graphics color as an illustration of the complement class. The outer circle represents the anonymous class of the owl:complementOf + statement, which is additionally indicated by the negation symbol ("¬") + used as a label. The anonymous class is connected to the class it is +composed of by a dashed line (without arrowhead).

+

Note that the set operators owl:unionOf and owl:intersectionOf + can also connect more than two classes, which is represented by +additional dashed lines from the anonymous class to those classes.

+
+ + + + + + + + + + + + + + + + + + + + + +
+ Table 8. Graphical representations of datatypes. +
Ontology elementGraphical representationDescription
rdfs:Datatype + + + Datatype + +

Rectangle in datatype color with solid border. The datatype label is the last part of the URI reference to the datatype (e.g. "dateTime", "boolean", etc.)

rdfs:Literal + + + Literal + +

Datatype representation with a dashed border and the label "Literal".

+

Note that OWL makes use of XML Schema datatypes.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 9. Representation of header information and individuals. +
Ontology elementGraphical representationDescription
owl:imports,
+ owl:versionInfo,
+ owl:priorVersion, owl:BackwardCompatibleWith, owl:incompatibleWith
+ + + Name of ontology + Ontology URI + Description: This is an example of how + an infobox with information from the + ontology header may look like. + +

Text in an infobox complementing the visualization.

Individuals

No graphical representation (or alternatively the graphical representation of VOWL 1.0).

It is recommended to separate the depiction of the +individuals from the rest of the visualization (e.g. by listing the +individuals of interactively selected classes in a sidebar).

+

Alternatively, individuals may be depicted as sections of + the circle that represents the class they are instances of (as +specified by VOWL 1.0).

Data values

No graphical representation

It is recommended to separate the depiction of the data values from the rest of the visualization.

+

OWL elements such as owl:allValuesFrom, owl:someValuesFrom, owl:hasValue, rdfs:comment, rdfs:seeAlso, rdfs:isDefinedBy, and owl:DataRange (rdfs:datatype + in OWL 2 which has a representation in the current specification) are +not part of the VOWL visualization but could be displayed in another way + (e.g. as text information in a tooltip or sidebar). This is also the +case for the OWL elements owl:Ontology, owl:differentFrom, owl:AllDifferent, owl:distinctMembers, owl:Restriction, owl:onProperty, owl:AnnotationProperty, and owl:OntologyProperty that serve as containers of other elements, link individuals, or define ontology metadata.

+
+
+
+

Example [back to top]

+

The following example visualizes the Friend of a Friend (FOAF) vocabulary (version 0.99) using VOWL. It has been created with WebVOWL, a web-based implementation of VOWL. Further examples are provided at vowl.visualdataweb.org. There is also a VOWL plugin for the popular ontology editor Protégé that implements the VOWL specification to a large extend.

+
+
+
+ focuslastNamegeekcodefamilyNamefirstNamemyersBr...planSurnameSubclass ofbasedNearjabber ID(inverse functional)past projectcurrent p...imagethumbnaildepictsdepictionworkpla...work in...publicationsschool...Subclass ofSubclass ofknowsSubclass ofinteresttipjarweblog(inverse functional)openidhomepage(inverse functional)pagetopicis primary...(functional)primary t...(inverse functional)sha1sum...account...Subclass ofSubclass ofSubclass ofaccount...memberSubclass ofage(functional)birthday(functional)gender(functional)statussha1sun...(inverse functional)AIM chat ID(inverse functional)ICQ chat ID(inverse functional)Yahoo ch...(inverse functional)MSN cha...(inverse functional)mademakerpersona...(inverse functional)topic_int...Subclass ofaccountphonefunded bylogo(inverse functional)themeDNA ch...Given namenicknameSkype IDtitlenameaccount(disjoint)(disjoint)Concept(external)ThingPerson[Person, Pe...]LiteralLiteralLiteralLiteralLiteralLiteralLiteralSpatial Thing(external)LiteralThingImage[ImageObject]ThingDocument[CreativeWork]PersonalPr...Agent[Agent]ThingOnline AccountOnline Chat...Online E-c...Online Gam...LiteralLiteralLiteralLiteralLiteralLiteralThingGroupProjectLiteralOrganizationLabel PropertyThingLiteralLiteralLiteralLiteralLiteralLiteralLiteralLiteralLiteralLiteral
+ +

Zooming is device-dependent: use mouse wheel, double click (+ shift key), or two fingers zooming gesture on the background.

+
+
+
+

Acknowledgments [back to top]

+

The authors would like to thank David Bold, Thomas Ertl, Vincent +Link, and Eduard Marbach for their valuable feedback, suggestions, and +support.

+
+
+
+

References [back to top]

+ +

Further information on a previous version of VOWL (VOWL 1.0) can be found in the following publications:

+ +

(References have last been updated on June 21, 2016)

+
+
+
+

Creative Commons LicenseThis work is licensed under the Creative Commons Attribution 4.0 + license. You are free to copy, distribute, transmit, remix, or adapt +the work, as long as you reference the work and its authors.

+
+
+ + + + + + + diff --git a/vowl_v2/index.orig b/vowl_v2/index.orig new file mode 100644 index 00000000..dd190269 --- /dev/null +++ b/vowl_v2/index.orig @@ -0,0 +1,1260 @@ + + + + + + + + + + +VOWL: Visual Notation for OWL Ontologies + + + +
+
+

VOWL: Visual Notation for OWL Ontologies

+

Specification of Version 2.0 – 7 April 2014

+
+
+
This version:
+
http://purl.org/vowl/spec/v2/
+
Latest version
+
http://purl.org/vowl/spec/
+
Previous version:
+
http://purl.org/vowl/spec/v1/
+
Authors:
+
Stefan Negru, Alexandru Ioan Cuza University
+ Steffen Lohmann, University of Stuttgart
+ Florian Haag, University of Stuttgart
+
+
+ visualdataweb.org »
+
+
+

Abstract

+

The Visual Notation for OWL Ontologies (VOWL) defines a visual +language for the user-oriented representation of ontologies. It provides + graphical depictions for elements of the Web Ontology Language (OWL) +that are combined to a force-directed graph layout visualizing the +ontology.

+

This specification focuses on the visualization of the ontology +schema (i.e. the classes, properties and datatypes, sometimes called +TBox), while it also includes recommendations on how to depict +individuals and data values (the ABox). Familiarity with OWL and other Semantic Web technologies is required to understand this specification.

+
+
+
+

Table of Contents

+
    +
  1. Overview
  2. +
  3. Basic Building Blocks
  4. +
  5. Visual Notation
  6. +
  7. Example
  8. +
  9. Acknowledgments
  10. +
  11. References
  12. +
+
+
+
+

Overview [back to top]

+

The Visual Notation for OWL Ontologies (VOWL) is based on only a handful of graphical primitives + forming the alphabet of the visual language: Classes are depicted as +circles that are connected by lines and arrows representing the property + relations. Property labels and datatypes are shown in rectangles. +Information on individuals and data values is either displayed in the +visualization itself or in another part of the user interface.

+

The second ingredient of VOWL is a color scheme + complementing the graphical primitives. It defines colors for the +visual elements to allow for an easy distinction of different types of +classes and properties. Although the color scheme is defined in an +abstract way leaving room for customization, a set of concrete color +recommendations provides guidance for developers.

+

Finally, the visual elements are combined to a graph that is +rendered in a force-directed layout and represents the ontology. VOWL +defines splitting rules to specify which elements are multiplied and thus displayed several times in the visualization to improve the overall layout.

+

VOWL can be used with any version of OWL (i.e. OWL 1 and OWL 2), + although not all language constructs (especially of OWL 2) are included + in this specification. Best results may be achieved with OWL DL or the more restrictive profiles OWL 2 EL/QL/RL, as well as OWL Lite. VOWL also provides graphical depictions for elements of RDF and RDFS that are reused in OWL, such as rdf:Property or rdfs:subClassOf.

+
+
+
+

Basic Building Blocks [back to top]

+

This section introduces the graphical primitives and color scheme that form the basic building blocks of VOWL. It also defines splitting rules for elements in the graph visualization and gives some general guidelines for using the notation.

+

Graphical Primitives

+

Table 1 lists all graphical primitives used in VOWL.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 1. Graphical primitives. +
NamePrimitiveDescriptionApplication
Circle + +

Each circle represents a class of the ontology. The +color of the circle depends on the type of class. There is an +implementation-specific default size for circles.

+

If an ontology contains individuals and unless purely the + schema (i.e. the TBox) is considered, the circle can become larger than + the default size – in that case, its size corresponds to the number of +individuals that are instances of the class. VOWL does not specify a +particular function for mapping the number of individuals to the circle +size – good results may be achieved with a logarithmic or square-root +scaling in most cases. A maximum size may be imposed. + Individuals inferred from subclasses are counted as well +if reasoning is available and not deactivated.

+

The circles representing the special classes owl:Thing and rdfs:Resource + are exceptions. They are not scaled but have a fixed size that is +smaller than the default size of classes. In addition, the circles of +these two classes have a dashed border and are multiplied in the +visualization according to the splitting rules.

owl:Class, rdfs:Class, owl:DeprecatedClass, owl:Thing, rdfs:Resource
Line + + +

Lines are used to represent property relations. They usually have an arrowhead indicating the direction of the relation. The line style and arrowhead + to use are determined by the type of the property. If the same two +classes are connected by multiple lines (i.e. if there are multi-edges +between circle nodes in the graph visualization), the lines may be +curved.

rdfs:domain, rdfs:range, owl:disjointWith, rdfs:subClassOf, owl:unionOf, owl:intersectionOf, owl:complementOf
Arrowhead + + +

Arrowheads indicate the direction of property relations + by pointing to the object of the property – i.e., a datatype, class, or + class instance that is defined as the range of that property.

+

Arrowheads representing range axioms are filled with the foreground color; arrowheads representing subclass relations are filled with the neutral color.

rdfs:range (with foreground color), rdfs:subClassOf (with neutral color)

Rectangle + +

Property labels and datatypes are shown in rectangles. If representing datatypes, the rectangles have the datatype color and a border. If representing property labels, they are borderless and colored according to the property type.

rdfs:Datatype, rdfs:Literal, property labels

Line style + + +

The lines and borders of some types of classes and +properties are dashed or dotted. A dashed line indicates set operators +and class disjointness (if visualized). A dashed border indicates literals and special types of classes. A dotted line is reserved for subclass relations.

dotted line: rdfs:subClassOf;
+ dashed line: owl:disjointWith, owl:unionOf, owl:intersectionOf, owl:ComplementOf;
+ dashed border: owl:Thing, rdfs:Resource, rdfs:Literal, and anonymous classes (as part of set operators)

Text + + text + number + symbol + +

Text is used for labels and type information, numbers +represent cardinalities and symbols may complement schematic +illustrations. Moreover, an infobox with textual + information from the ontology header, such as the title and description + of the ontology, may be displayed in the visualization.

rdfs:label, type of property ("Subclass of" for rdfs:subClassOf), + additional type information in brackets (e.g. "deprecated", +"functional", etc.), symbols in schematic illustrations (e.g. union +symbol ("∪") for owl:unionOf), cardinalities, infobox

+

Color Scheme

+

Table 2 lists the colors used in VOWL. +They are defined in an abstract way, along with a description and a +recommendation for a concrete color, including its hex code. Developers +may choose different colors, as long as they comply with the abstract +descriptions. All colors are defined relative to the canvas color, + which is assumed to be very light. The colors (and color descriptions) +may be 'inverted' if the visualization is presented on a dark +background.

+

While the colors ease the reading of the visualization, they are +not required to understand it. The visualization is also understandable +if printed in black and white or read by color-blind people, though some + details may not be visible any longer (e.g. if a class is of type owl:Class or rdfs:Class). + If these details should also be available in black and white prints of +the visualization, they may be added as text (e.g. in the label of the +element).

+

There may be conflicts in using this +color scheme, e.g. when a deprecated class belongs to an external +ontology. They should be resolved by giving one of the colors a higher +priority and adding all information in the label and/or another part of +the user interface (e.g. a sidebar). Recommendations are given in the general guidelines.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 2. Color scheme. +
Abstract color nameConcrete color recommendationDescriptionApplication
Canvas#fffwhite

Very light color with a good contrast to all other colors.

background of the visualization

Neutral#fffwhite

Light color with a good contrast to all other colors (usually similar or identical to the canvas color).

owl:Thing, arrowhead of rdfs:subClassOf, double border of owl:equivalentClass

Foreground#000black

Very dark color with a good contrast to all other colors, except the external color.

lines, borders, arrowheads, text, numbers, symbols

General#acflight blue

Light color with a good contrast to the foreground color.

owl:Class, owl:ObjectProperty (incl. subclasses), owl:disjointWith

Rdf#c9clight purple

Color similar to the general color with a good contrast to the foreground color.

rdfs:Class, rdfs:Resource, rdf:Property

Deprecated#ccclight gray

Color that is clearly different from the other colors and that is associated with being 'deactivated'.

owl:DeprecatedClass, owl:DeprecatedProperty

External#36cdark blue

Dark version of the general color, with the text in the neutral color instead of the foreground color.

Classes and properties from other ontologies that are linked in the ontology being visualized.

Datatype#fc3yellow

Light color that is clearly different from the other colors.

rdfs:Datatype, rdfs:Literal

Datatype Property#9c6light green

Light color that is clearly different from the other colors.

owl:DatatypeProperty

Graphics#69cmedium blue

Darkened version of the general color.

Schematic illustrations in owl:disjointWith, owl:unionOf, owl:intersectionOf, owl:ComplementOf

Highlighting#f00red

Very visible color, clearly indicating that an element is hovered or selected.

circles, rectangles, lines, borders, arrowheads

Indirect Highlighting#f90orange

Color similar to the highlighting color.

rectangles, circles

+

Splitting Rules

+

While some generic elements do not carry important domain information (e.g. owl:Thing, rdfs:Literal), + they may be connected to a lot of other elements in the ontology. This +would result in many links in the graph visualization that could +negatively affect its layout and readability. In addition, these highly +connected elements would tend to stand out among the other elements, +giving them visual emphasis that does not adequately reflect their +importance in the ontology. Therefore, VOWL defines splitting rules for +some generic OWL elements.

+

Table 3 lists the two different splitting rules, along with the OWL elements they are applied to.

+ + + + + + + + + + + + + + + + + + + + + +
+ Table 3. Splitting rules. +
NameDescriptionApplication
Splitting by property

The element is visualized once for every property it is linked to, i.e. if an element is linked to m properties, it is represented m times.

rdfs:Datatype, rdfs:Literal

Splitting by class

The element is visualized once for every class it is linked to (via property relations), i.e. if an element is linked to n classes, it is represented n times – independently of how often the element is linked to each class.

owl:Thing, rdfs:Resource

+

Note that each link of a splitted element is connected to only one of its representations in the graph visualization, not to all of them. Also note the other VOWL guidelines for the visualization of owl:Thing.

+

Elements that are defined to be equivalent (using owl:equivalentProperty or owl:equivalentClass) are, on the contrary, represented by only one visual element in the graph.

+
+

General Guidelines

+

Some general guidelines and recommendations for the usage and implementation of VOWL are listed in the following:

+

Labels

+

If elements do not have an rdfs:label, + it is recommended to take the last part of the URI as label, i.e. the +part that follows the last slash (/) or hash (#) character. Labels may +be abbreviated if they do not fit in the available space (e.g. +"Winnie-the-Pooh" → "Winnie…"). The full label should be shown on demand + in these cases (e.g. in a tooltip or sidebar).

+

Graph Layout

+

The visual elements are combined to a graph that should be +rendered in an appealing and readable layout. The positions of the +circles should be roughly determined by the number of inbound and +outbound property relations, i.e. the more property relations a class +has, the more centric its circle representation in the layout. It is +recommended to use a force-directed graph layout (though other layouts +may be equally or even more appropriate in certain cases). The users +should be enabled to adapt the graph layout (e.g. by repositioning the +nodes that represent the classes and datatypes).

+

Missing Domain and/or Range Information

+

If no domain and/or range axiom is defined for a property, owl:Thing should be used as domain and/or range. An exception are datatype properties without a defined range, where rdfs:Literal is used as range instead.

+

Visualization of owl:Thing

+

The visual representation of owl:Thing should only be used if either no domain and/or range axiom is defined for a property, or if owl:Thing is explicitly defined as domain and/or range. It is not recommended to visualize subclass relations of owl:Thing, as every user-defined class is implicitly a subclass of owl:Thing and the subclass relations would unnecessarily clutter the visualization.

+

External Elements

+

Elements whose base URI differs from that of the visualized +ontology may be marked as external (this feature is optional). +Developers may define different colors to visually group external +elements by their base URI, as long as they use the representation with +'inverted coloring' (i.e. dark color with light font) defined for +external elements (i.e. external classes and external properties).

+

Interactive Highlighting

+

The interactive highlighting assists in the visual exploration of + the ontology by indicating hovered, selected, and related elements. +Three modes of interactive highlighting are distinguished, two of which +are direct:

+
    +
  1. Highlight on hover: changes the fill color of the hovered element (plus the color of the line and arrow if any) to the highlighting color. This highlighting mode is dependent on the interaction context (e.g., it may not be supported by many touch interfaces).
  2. +
  3. Highlight on selection: changes the border color of the selected element (plus the color of the line and arrow if any) to the highlighting color. Note that it should also be possible to deselect elements that have been selected.
  4. +
  5. The third highlighting mode is +indirect. It expresses some kind of relationship between elements +without connecting them by a line. It is used to interactively indicate +sub- and superproperties of a hovered property. Like the highlight on hover, + it changes the fill color of the element (though not necessarily the +color of the line and arrow if any), but this time to the indirect highlighting color.
  6. +
+

Conflicts

+

The deprecated color has priority over the external color, i.e. if a class or property from an external ontology is deprecated, it should be visualized in the deprecated color. + In such cases, the type information displayed in brackets will include +all information in a comma-separated form (e.g. "deprecated, external"). + If a property is symmetric and functional, the type information should +be "symmetric, functional" accordingly.

+
+
+
+

Visual Notation [back to top]

+

The following tables list the graphical representations for the +different OWL elements (and some RDF and RDFS elements reused by OWL). +They are provided as interactive Scalable Vector Graphics (SVG) and implement the highlight on hover effects.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 4. Graphical representations of classes. +
Ontology elementGraphical representationDescription
owl:Class + + + Class + +

Circle in general color showing the class label in the selected language.

rdfs:Class + + + Class + +

Class representation in rdf color.

External class
+ (different base URI)
+ + + + Class + (external) + + +

Class representation in external color and with indication "external" in brackets (same representation for external owl:Class and rdfs:Class).

owl:DeprecatedClass + + + + Class + (deprecated) + + +

Class representation in deprecated color and with indication "deprecated" in brackets (same representation for deprecated owl:Class and rdfs:Class). + This graphical representation is also used for deprecated external +classes, with indication "deprecated, external" in brackets.

owl:Thing
+ (owl:Nothing)
+ + + Thing + +

Smaller circle in neutral color with a dashed border and label "Thing". This graphical representation is multiplied in the visualization according to the splitting rules. The same representation with label "Nothing" may be used to represent owl:Nothing (though it is generally not recommended to include owl:Nothing in the visualization at all).

rdfs:Resource + + + Resource + +

Smaller circle in rdf color with a dashed border and label "Resource". This graphical representation is multiplied in the visualization according to the splitting rules.

+

Note that the text string "Class" is used as a placeholder for the actual class label + in the graphical representations. In contrast, the text strings in +brackets (i.e. "external" and "deprecated") and the labels "Thing" and +"Resource" are not placeholders but literally shown in the +visualization.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 5. Graphical representations of properties. +
Ontology elementGraphical representationDescription
rdfs:domain, rdfs:range + + + Class A + + + + + + + + Class B + +

Solid line starting at the domain with an arrowhead in the foreground color + that points to the range. This graphical representation does never +occur on its own but always in combination with the property for which +the domain and range have been defined (missing domain or range information is replaced).

owl:ObjectProperty + + + Class A + + + + + + + + ObjectProperty + + + + Class B + +

Property representation showing the property label in a rectangle having the general color.

owl:DatatypeProperty + + + Class A + + + + + + + + DatatypeProperty + + + + Datatype + +

Property representation showing the property label in a rectangle having the datatype property color .

rdf:Property + + + Class A + + + + + + + + Property + + + + Class B + +

Property representation showing the property label in a rectangle having the rdf color.

External property
+ (different base URI)
+ + + Class A + + + + + + + + Property + + + + + Class B + +

Property representation showing the property label in a rectangle having the external color (same representation for external owl:ObjectProperty, owl:DatatypeProperty, and rdf:Property).

owl:DeprecatedProperty + + + Class A + + + + + + + + DeprecatedProperty + + + + Class B + +

Property representation showing the property label in a rectangle having the deprecated color (same representation for deprecated owl:ObjectProperty, owl:DatatypeProperty, rdf:Property, and external properties.)

owl:FunctionalProperty + + + Class A + + + + + + + + + Property + (functional) + + + + + Class B + +

Property representation with indication "functional" +in brackets. The color of the rectangle depends on the type of property, + i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

+

The global cardinality constraint of functional +properties is not made explicit in the visualization to avoid any +confusion with cardinality constraints defined with owl:cardinality, owl:minCardinality, and owl:maxCardinality that are displayed in the visualization.

owl:InverseFunctionalProperty + + + Class A + + + + + + + + + ObjectProperty + (inverse functional) + + + + + Class B + +

Object property representation with indication "inverse + functional" in brackets. The global cardinality constraint of inverse +functional properties is not made explicit in the visualization for the +same reason as for functional properties.

owl:TransitiveProperty + + + Class A + + + + + + + + + ObjectProperty + (transitive) + + + + + Class B + +

Object property representation with indication "transitive" in brackets.

Properties with identical domain and range + + + + + + + Class A + + + + ObjectProperty + +

Object property representation with the line starting and ending at the same class representation (reflexive property representation). + If there are several of these properties, their representations should +be placed around the circle in a way that maintains readability.

owl:SymmetricProperty + + + + + + + Class A + + + + + ObjectProperty + (symmetric) + + +

Reflexive property representation with indication "symmetric" in brackets.

+

Note that the text strings "Property", "ObjectProperty", +"DatatypeProperty", and "DeprecatedProperty" are used as placeholders +for the actual property labels in the graphical +representations. In contrast, the text strings in brackets (i.e. +"functional", "inverse functional", "transitive", and "symmetric") are +not placeholders but literally shown in the visualization.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 6. Graphical representations of further properties. +
Ontology elementGraphical representationDescription
owl:cardinality,
+ owl:minCardinality, owl:maxCardinality
+ + + Class A + + + + + + + + Property + + + + x..y + + + + + Class B + +

Exact, minimal, and maximal cardinality constraints +are written as numbers near the end of the property arrow. The +representation is similar to the UML notation for cardinalities, + i.e. the letters "x" and "y" in the example represent the minimum and +maximum cardinality for that property. Exact cardinalities are +represented by only one number, while the asterisk (*) denotes an +unrestricted cardinality. Examples are "0..1" for a cardinality of 0 to +1, "1..*" for a minimum cardinality of 1, or "3" for a cardinality of +exactly 3.

+

The default cardinality of most properties is any number + (i.e. zero or more) and would be represented by a sole asterisk. +However, it is recommended to only depict cardinalities that are +explicitly specified with owl:cardinality, owl:minCardinality, and owl:maxCardinality. Default property cardinalities (incl. the global cardinality constraints of functional and inverse functional properties) are better not shown in the visualization to avoid confusion and reduce visual clutter.

+

The color of the rectangle depends on the type of property, i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

owl:disjointWith + + + Class A + + + + + + + + + + + + + (disjoint) + + + + + Class B + +

Dashed line without arrowhead connecting the disjoint +classes, accompanied by a Venn diagram illustration of two disjoint +sets. The illustration has the graphics color and is shown in a rectangle colored in the general color, along with the indication "disjoint" in brackets.

+

If several classes are pairwise disjoint, this could be +visualized by connecting each two of them. As an alternative to showing +this element in the visualization, owl:disjointWith + statements may be presented as details on demand in another part of the + user interface, which is recommended since it usually results in a less + cluttered graph.

rdfs:subClassOf + + + Class A + + + + + + + + Subclass of + + + + Class B + +

Dotted line starting at the subclass with an arrowhead filled with the neutral color that points to the superclass. The representation is similar to the UML notation for generalizations + but with a dashed line instead of a solid one to make it clearly +distinguishable from other property relations. In addition, it is +recommended to add the label "Subclass of" to the representation to +clarify the semantics of the relation. The label has either a +transparent background (unless highlighted) or is shown in a rectangle +that has the neutral color, which is recommended.

rdfs:subPropertyOf + + + + + + + + + + + Class A + + + + + Property + + + + Subproperty + + + + + Class B + +

If a property is hovered, its sub- and superproperties (if any) may be dynamically highlighted using the indirect highligthing color and mode. + The color of the rectangle depends on the type of property, i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

owl:inverseOf + + + Class A + + + + + + + + + + + + + + ObjectProperty + + + + InverseProperty + + + + + Class B + +

Object property representation with arrowheads at both +ends, annotated with the label of the property and its inverse +counterpart (interactive highlighting of direction). In order to +indicate which label denotes which direction in non-interactive +contexts, each label may be slightly displaced toward its respective +arrowhead (not shown in the example).

owl:equivalentProperty + + + Class A + + + + + + + + + Property A + [Property B] + + + + + Class B + +

This graphical representation is used for two or more properties that are defined to be equivalent. One of the property labels is the main label, while the rest is listed in square brackets (abbreviated if they do not all fit). The main label is taken from a property with the same base URI as the ontology. If there is no such property (i.e. all properties are external), it is taken from any of the properties.

+

The color of the rectangle depends on the type of property from which the main label is taken, i.e. general color = owl:ObjectProperty, datatype property color = owl:DatatypeProperty, and rdf color = rdf:Property.

owl:equivalentClass + + + + + Class A + [Class B] + + +

Class representation with a double border. The space between the two borders has the neutral color. This graphical representation is used for two or more classes that are defined to be equivalent. One of the class labels is the main label, while the rest is listed in square brackets (abbreviated if they do not all fit). The main label is taken from a class with the same base URI as the ontology. If there is no such class (i.e. all classes are external), + it is taken from any of the classes. Note that the graphical +representation has always a double border, independently of how many +classes it represents.

+

The color of the circle depends on the type of class from which the main label is taken, i.e. general color = owl:Class, datatype property color = rdfs:Class, external color = external class, and deprecated color = owl:deprecatedClass.

+

The graphical representations of equivalent classes may also be used to represent owl:sameAs relations that can be defined between classes in OWL Full.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 7. Graphical representations of set operators. +
Ontology elementGraphical representationDescription
owl:unionOf + + + Class A + + + + + + + + + + + + + + + + + + + Class B + +

Class representation with a dashed border and a Venn diagram of two united sets colored in the graphics color. The circle represents the anonymous class of the owl:unionOf + statement, which is additionally indicated by the union symbol ("∪") +used as a label. The anonymous class is connected to the classes it is +composed of by a dashed line (without arrowhead).

owl:intersectionOf + + + Class A + + + + + + + + + + + + + + + + + + + Class B + +

Class representation with a dashed border and a Venn diagram of two intersected sets colored in the graphics color. The circle represents the anonymous class of the owl:intersectionOf + statement, which is additionally indicated by the intersection symbol +("∩") used as a label. The anonymous class is connected to the classes +it is composed of by a dashed line (without arrowhead).

owl:complementOf + + + Class + + + + + + + + + + + +

Class representation with a dashed border containing a smaller circle in the graphics color as an illustration of the complement class. The outer circle represents the anonymous class of the owl:complementOf + statement, which is additionally indicated by the negation symbol ("¬") + used as a label. The anonymous class is connected to the class it is +composed of by a dashed line (without arrowhead).

+

Note that the set operators owl:unionOf and owl:intersectionOf + can also connect more than two classes, which is represented by +additional dashed lines from the anonymous class to those classes.

+
+ + + + + + + + + + + + + + + + + + + + + +
+ Table 8. Graphical representations of datatypes. +
Ontology elementGraphical representationDescription
rdfs:Datatype + + + Datatype + +

Rectangle in datatype color with solid border. The datatype label is the last part of the URI reference to the datatype (e.g. "dateTime", "boolean", etc.)

rdfs:Literal + + + Literal + +

Datatype representation with a dashed border and the label "Literal".

+

Note that OWL makes use of XML Schema datatypes.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Table 9. Representation of header information and individuals. +
Ontology elementGraphical representationDescription
owl:imports,
+ owl:versionInfo,
+ owl:priorVersion, owl:BackwardCompatibleWith, owl:incompatibleWith
+ + + Name of ontology + Ontology URI + Description: This is an example of how + an infobox with information from the + ontology header may look like. + +

Text in an infobox complementing the visualization.

Individuals

No graphical representation (or alternatively the graphical representation of VOWL 1.0).

It is recommended to separate the depiction of the +individuals from the rest of the visualization (e.g. by listing the +individuals of interactively selected classes in a sidebar).

+

Alternatively, individuals may be depicted as sections of + the circle that represents the class they are instances of (as +specified by VOWL 1.0).

Data values

No graphical representation

It is recommended to separate the depiction of the data values from the rest of the visualization.

+

OWL elements such as owl:allValuesFrom, owl:someValuesFrom, owl:hasValue, rdfs:comment, rdfs:seeAlso, rdfs:isDefinedBy, and owl:DataRange (rdfs:datatype + in OWL 2 which has a representation in the current specification) are +not part of the VOWL visualization but could be displayed in another way + (e.g. as text information in a tooltip or sidebar). This is also the +case for the OWL elements owl:Ontology, owl:differentFrom, owl:AllDifferent, owl:distinctMembers, owl:Restriction, owl:onProperty, owl:AnnotationProperty, and owl:OntologyProperty that serve as containers of other elements, link individuals, or define ontology metadata.

+
+
+
+

Example [back to top]

+

The following example visualizes the Friend of a Friend (FOAF) vocabulary (version 0.99) using VOWL. It has been created with WebVOWL, a web-based implementation of VOWL. Further examples are provided at vowl.visualdataweb.org. There is also a VOWL plugin for the popular ontology editor Protégé that implements the VOWL specification to a large extend.

+
+
+
+ focuslastNamegeekcodefamilyNamefirstNamemyersBr...planSurnameSubclass ofbasedNearjabber ID(inverse functional)past projectcurrent p...imagethumbnaildepictsdepictionworkpla...work in...publicationsschool...Subclass ofSubclass ofknowsSubclass ofinteresttipjarweblog(inverse functional)openidhomepage(inverse functional)pagetopicis primary...(functional)primary t...(inverse functional)sha1sum...account...Subclass ofSubclass ofSubclass ofaccount...memberSubclass ofage(functional)birthday(functional)gender(functional)statussha1sun...(inverse functional)AIM chat ID(inverse functional)ICQ chat ID(inverse functional)Yahoo ch...(inverse functional)MSN cha...(inverse functional)mademakerpersona...(inverse functional)topic_int...Subclass ofaccountphonefunded bylogo(inverse functional)themeDNA ch...Given namenicknameSkype IDtitlenameaccount(disjoint)(disjoint)Concept(external)ThingPerson[Person, Pe...]LiteralLiteralLiteralLiteralLiteralLiteralLiteralSpatial Thing(external)LiteralThingImage[ImageObject]ThingDocument[CreativeWork]PersonalPr...Agent[Agent]ThingOnline AccountOnline Chat...Online E-c...Online Gam...LiteralLiteralLiteralLiteralLiteralLiteralThingGroupProjectLiteralOrganizationLabel PropertyThingLiteralLiteralLiteralLiteralLiteralLiteralLiteralLiteralLiteralLiteral
+ +

Zooming is device-dependent: use mouse wheel, double click (+ shift key), or two fingers zooming gesture on the background.

+
+
+
+

Acknowledgments [back to top]

+

The authors would like to thank David Bold, Thomas Ertl, Vincent +Link, and Eduard Marbach for their valuable feedback, suggestions, and +support.

+
+
+
+

References [back to top]

+ +

Further information on a previous version of VOWL (VOWL 1.0) can be found in the following publications:

+ +

(References have last been updated on June 21, 2016)

+
+
+
+

Creative Commons LicenseThis work is licensed under the Creative Commons Attribution 4.0 + license. You are free to copy, distribute, transmit, remix, or adapt +the work, as long as you reference the work and its authors.

+
+
+ + + + + + + diff --git a/vowl_v2/js/data/foaf_spec.json b/vowl_v2/js/data/foaf_spec.json new file mode 100644 index 00000000..fcbd3880 --- /dev/null +++ b/vowl_v2/js/data/foaf_spec.json @@ -0,0 +1,127 @@ +{ + "info": [ + { + "title": "Friend of a Friend (FOAF) vocabulary", + "url": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/", + "version": "0.99 (Jan 2014)", + "authors": "Dan Brickley, Libby Miller", + "description": "The Friend of a Friend (FOAF) RDF vocabulary, described using W3C RDF Schema and the Web Ontology Language." + } + ], + "nodes": [ + {"name": "Concept", "type": "external", "uri": "http://www.w3.org/2004/02/skos/core#Concept"}, + {"name": "Thing", "type": "thing", "uri": "http://www.w3.org/2002/07/owl#Thing"}, + {"name": "Person", "type": "equivalent", "equivalentClasses": [{"name": "Person", "uri": "http://www.w3.org/2000/10/swap/pim/contact#Person"}, {"name": "Person", "uri": "https://web.archive.org/web/20210403232056/http://schema.org/Person"}], "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Person", "disjoints": [{"name": "Organization", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Organization"}, {"name": "Project", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Project"}]}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Spatial Thing", "type": "external", "uri": "http://www.w3.org/2003/01/geo/wgs84_pos#SpatialThing"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Thing", "type": "thing", "uri": "http://www.w3.org/2002/07/owl#Thing"}, + {"name": "Image", "type": "equivalent", "equivalentClasses": [{"name": "ImageObject", "uri": "https://web.archive.org/web/20210403232056/http://schema.org/ImageObject"}], "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Image"}, + {"name": "Thing", "type": "thing", "uri": "http://www.w3.org/2002/07/owl#Thing"}, + {"name": "Document", "type": "equivalent", "equivalentClasses": [{"name": "CreativeWork", "uri": "https://web.archive.org/web/20210403232056/http://schema.org/CreativeWork"}], "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Document", "disjoints": [{"name": "Organization", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Organization"}, {"name": "Project", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Project"}]}, + {"name": "PersonalProfileDocument", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/PersonalProfileDocument"}, + {"name": "Agent", "equivalentClasses": [{"name": "Agent", "uri": "https://web.archive.org/web/20210403232056/http://purl.org/dc/terms/Agent"}], "type": "equivalent", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Agent"}, + {"name": "Thing", "type": "thing", "uri": "http://www.w3.org/2002/07/owl#Thing"}, + {"name": "Online Account", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/OnlineAccount"}, + {"name": "Online Chat Account", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/OnlineChatAccount"}, + {"name": "Online E-commerce account", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/OnlineEcommerceAccount"}, + {"name": "Online Gaming Account", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/OnlineGamingAccount"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Thing", "type": "thing", "uri": "http://www.w3.org/2002/07/owl#Thing"}, + {"name": "Group", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Group"}, + {"name": "Project", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Project", "disjoints": [{"name": "Person", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Person"}, {"name": "Document", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Document"}]}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Organization", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Organization", "disjoints": [{"name": "Person", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Person"}, {"name": "Document", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Document"}]}, + {"name": "Label Property", "type": "class", "uri": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/LabelProperty"}, + {"name": "Thing", "type": "thing", "uri": "http://www.w3.org/2002/07/owl#Thing"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"}, + {"name": "Literal", "type": "literal", "uri": "http://www.w3.org/2000/01/rdf-schema#Literal"} + ], + "links": [ + {"source": 0, "target": 1, "valueTo": "focus", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/focus"}, + {"source": 2, "target": 3, "valueTo": "lastName", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/lastName"}, + {"source": 2, "target": 4, "valueTo": "geekcode", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/geekcode"}, + {"source": 2, "target": 5, "valueTo": "familyName", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/familyName"}, + {"source": 2, "target": 6, "valueTo": "firstName", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/firstName"}, + {"source": 2, "target": 7, "valueTo": "myersBriggs", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/myersBriggs"}, + {"source": 2, "target": 8, "valueTo": "plan", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/plan"}, + {"source": 2, "target": 9, "valueTo": "Surname", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/Surname"}, + {"source": 2, "target": 10, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 10, "target": 10, "valueTo": "basedNear", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/based_near"}, + {"source": 17, "target": 11, "valueTo": "jabber ID", "propertyTo": "datatype", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/jabberID"}, + {"source": 2, "target": 12, "valueTo": "past project", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/pastProject"}, + {"source": 2, "target": 12, "valueTo": "current project", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/currentProject"}, + {"source": 2, "target": 13, "valueTo": "image", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/img", "subpropertiesTo" : [{"id": 15, "direction": "from"}]}, + {"source": 13, "target": 13, "valueTo": "thumbnail", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/thumbnail"}, + {"source": 13, "target": 14, "valueTo": "depicts", "inverse": true, "valueFrom": "depiction", "subpropertiesFrom" : [{"id": 13}], "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/depicts", "uriFrom": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/depiction"}, + {"source": 2, "target": 15, "valueTo": "workplace homepage", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/workplaceHomepage"}, + {"source": 2, "target": 15, "valueTo": "work info homepage", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/workplaceInfoHomepage"}, + {"source": 2, "target": 15, "valueTo": "publications", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/publications"}, + {"source": 2, "target": 15, "valueTo": "schoolHomepage", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/schoolHomepage"}, + {"source": 13, "target": 15, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 16, "target": 15, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 2, "target": 2, "valueTo": "knows", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/knows"}, + {"source": 2, "target": 17, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 17, "target": 15, "valueTo": "interest", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/interest"}, + {"source": 17, "target": 15, "valueTo": "tipjar", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/tipjar", "subpropertiesTo" : [{"id": 29, "direction": "to"}]}, + {"source": 17, "target": 15, "valueTo": "weblog", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/weblog", "subpropertiesTo" : [{"id": 29, "direction": "to"}]}, + {"source": 17, "target": 15, "valueTo": "openid", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/openid", "subpropertiesTo" : [{"id": 30, "direction": "to"}]}, + {"source": 18, "target": 15, "valueTo": "homepage", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/homepage", "subpropertiesTo" : [{"id": 29, "direction": "to"}, {"id": 30, "direction": "to"}]}, + {"source": 18, "target": 15, "valueTo": "page", "inverse": true, "valueFrom": "topic", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/page", "uriFrom": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/topic", "subpropertiesTo" : [{"id": 28}, {"id": 30}, {"id": 26}, {"id": 25}]}, + {"source": 18, "target": 15, "valueTo": "is primary topic of", "inverse": true, "valueFrom": "primary topic", "typeTo": "functional", "properytFrom": "object", "typeFrom": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/isPrimaryTopicOf", "uriFrom": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/primaryTopic", "subpropertiesTo" : [{"id": 29, "direction": "to"}, {"id": 28}, {"id": 27}]}, + {"source": 15, "target": 42, "valueTo": "sha1sum (hex)", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/sha1"}, + {"source": 19, "target": 15, "valueTo": "account service homepage", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/accountServiceHomepage"}, + {"source": 20, "target": 19, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 21, "target": 19, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 22, "target": 19, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 19, "target": 32, "valueTo": "account name", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/accountName"}, + {"source": 30, "target": 17, "valueTo": "member", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/member"}, + {"source": 30, "target": 17, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 17, "target": 23, "valueTo": "age", "propertyTo": "datatype", "typeTo": "functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/age"}, + {"source": 17, "target": 24, "valueTo": "birthday", "propertyTo": "datatype", "typeTo": "functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/birthday"}, + {"source": 17, "target": 25, "valueTo": "gender", "propertyTo": "datatype", "typeTo": "functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/gender"}, + {"source": 17, "target": 26, "valueTo": "status", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/status"}, + {"source": 17, "target": 27, "valueTo": "sha1sunm of a personal mailbox URI name", "propertyTo": "datatype", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/mbox_sha1sum"}, + {"source": 17, "target": 28, "valueTo": "AIM chat ID", "propertyTo": "datatype", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/aimChatID", "subpropertiesTo" : [{"id": 59}]}, + {"source": 17, "target": 43, "valueTo": "ICQ chat ID", "propertyTo": "datatype", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/icqChatID", "subpropertiesTo" : [{"id": 59}]}, + {"source": 17, "target": 44, "valueTo": "Yahoo chat ID", "propertyTo": "datatype", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/yahooChatID", "subpropertiesTo" : [{"id": 59}]}, + {"source": 17, "target": 45, "valueTo": "MSN chat ID", "propertyTo": "datatype", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/msnChatID", "subpropertiesTo" : [{"id": 59}]}, + {"source": 17, "target": 29, "valueTo": "made", "inverse": true, "valueFrom": "maker", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/made", "uriFrom": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/maker"}, + {"source": 17, "target": 29, "valueTo": "personal mailbox", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/mbox"}, + {"source": 17, "target": 29, "valueTo": "topic_interest", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/topic_interest"}, + {"source": 33, "target": 17, "type": "dotted", "valueTo": "Subclass of", "propertyTo": "subclass", "uriTo": "http://www.w3.org/2000/01/rdf-schema#subClassOf"}, + {"source": 17, "target": 19, "valueTo": "account", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/account"}, + {"source": 35, "target": 35, "valueTo": "phone", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/phone"}, + {"source": 35, "target": 35, "valueTo": "funded by", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/fundedBy"}, + {"source": 35, "target": 35, "valueTo": "logo", "typeTo": "inverse functional", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/logo"}, + {"source": 35, "target": 35, "valueTo": "theme", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/theme"}, + {"source": 35, "target": 36, "valueTo": "DNA checksum", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/dnaChecksum"}, + {"source": 35, "target": 37, "valueTo": "Given name", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/givenName"}, + {"source": 35, "target": 38, "valueTo": "nickname", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/nick", "subpropertiesTo" : [{"id": 44}, {"id": 45}, {"id": 46}, {"id": 47}, {"id": 60}]}, + {"source": 17, "target": 41, "valueTo": "Skype ID", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/skypeID", "subpropertiesTo" : [{"id": 59}]}, + {"source": 35, "target": 39, "valueTo": "title", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/title"}, + {"source": 35, "target": 40, "valueTo": "name", "propertyTo": "datatype", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/name"}, + {"source": 17, "target": 19, "valueTo": "account", "uriTo": "https://web.archive.org/web/20210403232056/http://xmlns.com/foaf/0.1/holdsAccount"}, + {"source": 2, "target": 15, "type": "special", "propertyTo": "disjoint"}, + {"source": 2, "target": 31, "type": "special", "propertyTo": "disjoint"} + ] +}